diff --git a/app/src/routes/login/login.test.ts b/app/src/routes/login/login.test.ts
new file mode 100644
index 0000000000..512f4493c5
--- /dev/null
+++ b/app/src/routes/login/login.test.ts
@@ -0,0 +1,114 @@
+import { createTestingPinia } from '@pinia/testing';
+import { mount } from '@vue/test-utils';
+import { GlobalMountOptions } from '@vue/test-utils/dist/types';
+import { setActivePinia } from 'pinia';
+import { beforeEach, expect, test, vi } from 'vitest';
+import { createI18n } from 'vue-i18n';
+
+import vIcon from '@/components/v-icon/v-icon.vue';
+import vImage from '@/components/v-image.vue';
+import vSelect from '@/components/v-select/v-select.vue';
+import MarkdownDirective from '@/directives/markdown';
+import { useAppStore } from '@/stores/app';
+import publicView from '@/views/public/public-view.vue';
+import ContinueAs from './components/continue-as.vue';
+import SsoLinks from './components/sso-links.vue';
+import LdapForm from './components/login-form/ldap-form.vue';
+import LoginForm from './components/login-form/login-form.vue';
+import { useServerStore } from '@/stores/server';
+
+import LoginComponent from './login.vue';
+
+const i18n = createI18n({ legacy: false });
+
+const global: GlobalMountOptions = {
+ components: { publicView, vSelect, vIcon, vImage },
+ directives: { md: MarkdownDirective },
+ stubs: { publicView: false },
+ plugins: [i18n],
+};
+
+// silences locale message not found warnings
+vi.spyOn(i18n.global, 't').mockImplementation((key: any) => key);
+
+beforeEach(() => {
+ setActivePinia(
+ createTestingPinia({
+ createSpy: vi.fn,
+ stubActions: false,
+ initialState: {
+ serverStore: {
+ info: {
+ project: {
+ project_name: null,
+ project_descriptor: null,
+ project_logo: null,
+ project_color: '#6644FF', // ensure Color() usage in public-view doesn't cause error
+ default_language: null,
+ public_foreground: null,
+ public_background: null,
+ public_note: null,
+ custom_css: null,
+ },
+ },
+ },
+ },
+ })
+ );
+});
+
+test('show continue-as when authenticated', () => {
+ const appStore = useAppStore();
+ appStore.authenticated = true;
+
+ const wrapper = mount(LoginComponent, { global, shallow: true });
+
+ expect(wrapper.findComponent(ContinueAs).exists()).toBe(true);
+ expect(wrapper.findComponent(LdapForm).exists()).toBe(false);
+ expect(wrapper.findComponent(LoginForm).exists()).toBe(false);
+ expect(wrapper.findComponent(SsoLinks).exists()).toBe(false);
+});
+
+test('show login form and sso links when unauthenticated', () => {
+ const appStore = useAppStore();
+ appStore.authenticated = false;
+
+ const wrapper = mount(LoginComponent, { global, shallow: true });
+
+ expect(wrapper.findComponent(ContinueAs).exists()).toBe(false);
+ expect(wrapper.findComponent(LdapForm).exists()).toBe(false);
+ expect(wrapper.findComponent(LoginForm).exists()).toBe(true);
+ expect(wrapper.findComponent(SsoLinks).exists()).toBe(true);
+});
+
+test('show login form when unauthenticated and driver is local', () => {
+ const appStore = useAppStore();
+ appStore.authenticated = false;
+
+ const serverStore = useServerStore();
+ serverStore.auth.disableDefault = true;
+ serverStore.auth.providers = [{ driver: 'local', name: 'localProvider' }];
+
+ const wrapper = mount(LoginComponent, { global, shallow: true });
+
+ expect(wrapper.findComponent(ContinueAs).exists()).toBe(false);
+ expect(wrapper.findComponent(LdapForm).exists()).toBe(false);
+ expect(wrapper.findComponent(LoginForm).exists()).toBe(true);
+ expect(wrapper.findComponent(SsoLinks).exists()).toBe(true);
+});
+
+test('show ldap form when unauthenticated and driver is ldap', () => {
+ const appStore = useAppStore();
+ appStore.authenticated = false;
+
+ const serverStore = useServerStore();
+ serverStore.auth.disableDefault = true;
+ serverStore.auth.providers = [{ driver: 'ldap', name: 'ldapProvider' }];
+
+ const wrapper = mount(LoginComponent, { global, shallow: true });
+
+ expect(wrapper.findComponent(ContinueAs).exists()).toBe(false);
+ expect(wrapper.findComponent(LdapForm).exists()).toBe(true);
+ expect(wrapper.findComponent(LoginForm).exists()).toBe(false);
+ expect(wrapper.findComponent(SsoLinks).exists()).toBe(true);
+});
diff --git a/app/src/routes/login/login.vue b/app/src/routes/login/login.vue
index aac052b109..688c45102e 100644
--- a/app/src/routes/login/login.vue
+++ b/app/src/routes/login/login.vue
@@ -11,7 +11,7 @@
-
+
@@ -62,7 +62,7 @@ const providerSelect = computed({
},
set(value: string) {
provider.value = value;
- driver.value = unref(auth).providers.find((provider) => provider.name === value)?.driver ?? 'default';
+ driver.value = unref(auth).providers.find((provider) => provider.name === value)?.driver ?? DEFAULT_AUTH_DRIVER;
},
});
diff --git a/app/src/stores/server.ts b/app/src/stores/server.ts
index 96b56cc1d3..0a560dc919 100644
--- a/app/src/stores/server.ts
+++ b/app/src/stores/server.ts
@@ -1,5 +1,5 @@
import api, { replaceQueue } from '@/api';
-import { AUTH_SSO_DRIVERS, DEFAULT_AUTH_PROVIDER } from '@/constants';
+import { AUTH_SSO_DRIVERS, DEFAULT_AUTH_DRIVER, DEFAULT_AUTH_PROVIDER } from '@/constants';
import { i18n } from '@/lang';
import { setLanguage } from '@/lang/set-language';
import formatTitle from '@directus/format-title';
@@ -76,7 +76,11 @@ export const useServerStore = defineStore('serverStore', () => {
.map((provider) => ({ text: formatTitle(provider.name), value: provider.name, driver: provider.driver }));
if (!auth.disableDefault) {
- options.unshift({ text: i18n.global.t('default_provider'), value: DEFAULT_AUTH_PROVIDER, driver: 'default' });
+ options.unshift({
+ text: i18n.global.t('default_provider'),
+ value: DEFAULT_AUTH_PROVIDER,
+ driver: DEFAULT_AUTH_DRIVER,
+ });
}
return options;