diff --git a/src/frontend/src/components/forms/AuthenticationForm.tsx b/src/frontend/src/components/forms/AuthenticationForm.tsx
index cc75bb2d02..66057b5ae3 100644
--- a/src/frontend/src/components/forms/AuthenticationForm.tsx
+++ b/src/frontend/src/components/forms/AuthenticationForm.tsx
@@ -107,12 +107,14 @@ export function AuthenticationForm() {
@@ -228,12 +230,14 @@ export function RegistrationForm() {
diff --git a/src/frontend/tests/pui_basic.spec.ts b/src/frontend/tests/pui_basic.spec.ts
deleted file mode 100644
index c1639caa36..0000000000
--- a/src/frontend/tests/pui_basic.spec.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { expect, test } from './baseFixtures.js';
-import { baseUrl, user } from './defaults.js';
-import { doLogin, doQuickLogin } from './login.js';
-
-test('Basic Login Test', async ({ page }) => {
- await doLogin(page);
-
- // Check that the username is provided
- await page.getByText(user.username);
-
- await expect(page).toHaveTitle(/^InvenTree/);
-
- // Go to the dashboard
- await page.goto(baseUrl);
- await page.waitForURL('**/platform');
-
- await page.getByText('InvenTree Demo Server -').waitFor();
-
- // Check that the username is provided
- await page.getByText(user.username);
-
- await expect(page).toHaveTitle(/^InvenTree/);
-
- // Go to the dashboard
- await page.goto(baseUrl);
- await page.waitForURL('**/platform');
-
- // Logout (via menu)
- await page.getByRole('button', { name: 'Ally Access' }).click();
- await page.getByRole('menuitem', { name: 'Logout' }).click();
-
- await page.waitForURL('**/platform/login');
- await page.getByLabel('username');
-});
-
-test('Quick Login Test', async ({ page }) => {
- await doQuickLogin(page);
-
- // Check that the username is provided
- await page.getByText(user.username);
-
- await expect(page).toHaveTitle(/^InvenTree/);
-
- // Go to the dashboard
- await page.goto(baseUrl);
- await page.waitForURL('**/platform');
-
- await page.getByText('InvenTree Demo Server - ').waitFor();
-
- // Logout (via URL)
- await page.goto(`${baseUrl}/logout/`);
- await page.waitForURL('**/platform/login');
- await page.getByLabel('username');
-});
diff --git a/src/frontend/tests/pui_login.spec.ts b/src/frontend/tests/pui_login.spec.ts
new file mode 100644
index 0000000000..90331a9ef5
--- /dev/null
+++ b/src/frontend/tests/pui_login.spec.ts
@@ -0,0 +1,97 @@
+import { expect, test } from './baseFixtures.js';
+import { baseUrl, logoutUrl, user } from './defaults.js';
+import { doLogin, doQuickLogin } from './login.js';
+
+test('Login - Basic Test', async ({ page }) => {
+ await doLogin(page);
+
+ // Check that the username is provided
+ await page.getByText(user.username);
+
+ await expect(page).toHaveTitle(/^InvenTree/);
+
+ // Go to the dashboard
+ await page.goto(baseUrl);
+ await page.waitForURL('**/platform');
+
+ await page.getByText('InvenTree Demo Server -').waitFor();
+
+ // Check that the username is provided
+ await page.getByText(user.username);
+
+ await expect(page).toHaveTitle(/^InvenTree/);
+
+ // Go to the dashboard
+ await page.goto(baseUrl);
+ await page.waitForURL('**/platform');
+
+ // Logout (via menu)
+ await page.getByRole('button', { name: 'Ally Access' }).click();
+ await page.getByRole('menuitem', { name: 'Logout' }).click();
+
+ await page.waitForURL('**/platform/login');
+ await page.getByLabel('username');
+});
+
+test('Login - Quick Test', async ({ page }) => {
+ await doQuickLogin(page);
+
+ // Check that the username is provided
+ await page.getByText(user.username);
+
+ await expect(page).toHaveTitle(/^InvenTree/);
+
+ // Go to the dashboard
+ await page.goto(baseUrl);
+ await page.waitForURL('**/platform');
+
+ await page.getByText('InvenTree Demo Server - ').waitFor();
+
+ // Logout (via URL)
+ await page.goto(`${baseUrl}/logout/`);
+ await page.waitForURL('**/platform/login');
+ await page.getByLabel('username');
+});
+
+/**
+ * Test various types of login failure
+ */
+test('Login - Failures', async ({ page }) => {
+ const loginWithError = async () => {
+ await page.getByRole('button', { name: 'Log In' }).click();
+ await page.getByText('Login failed').waitFor();
+ await page.getByText('Check your input and try again').waitFor();
+ await page.locator('#login').getByRole('button').click();
+ };
+
+ // Navigate to the 'login' page
+ await page.goto(logoutUrl);
+ await expect(page).toHaveTitle(/^InvenTree.*$/);
+ await page.waitForURL('**/platform/login');
+
+ // Attempt login with invalid credentials
+ await page.getByLabel('login-username').fill('invalid user');
+ await page.getByLabel('login-password').fill('invalid password');
+
+ await loginWithError();
+
+ // Attempt login with valid (but disabled) user
+ await page.getByLabel('login-username').fill('ian');
+ await page.getByLabel('login-password').fill('inactive');
+
+ await loginWithError();
+
+ // Attempt login with no username
+ await page.getByLabel('login-username').fill('');
+ await page.getByLabel('login-password').fill('hunter2');
+
+ await loginWithError();
+
+ // Attempt login with no password
+ await page.getByLabel('login-username').fill('ian');
+ await page.getByLabel('login-password').fill('');
+
+ await loginWithError();
+
+ await page.waitForTimeout(2500);
+});