From 9b9d2825f1f381328ac2828ff2bd6e296d8717ad Mon Sep 17 00:00:00 2001 From: roble Date: Sat, 29 Aug 2026 17:12:48 +0100 Subject: [PATCH 1/3] feat: enhance Profile.vue with socialite provider management and add e2e tests for disconnect functionality --- resources/js/vue/pages/Profile.vue | 73 ++++++++++++++++--- .../tests/profile/socialite.settings.spec.ts | 51 +++++++++++++ 2 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 tests/e2e/tests/profile/socialite.settings.spec.ts diff --git a/resources/js/vue/pages/Profile.vue b/resources/js/vue/pages/Profile.vue index b1529d6..451ec95 100644 --- a/resources/js/vue/pages/Profile.vue +++ b/resources/js/vue/pages/Profile.vue @@ -22,7 +22,7 @@ import { import Separator from '@/components/ui/separator/Separator.vue'; import SettingsLayout from '@/layouts/SettingsLayout.vue'; import type { User } from '@/types'; -import { Link, router } from '@inertiajs/vue3'; +import { Link, router, usePage } from '@inertiajs/vue3'; import { Loader2 } from 'lucide-vue-next'; import { computed, ref } from 'vue'; import IconGithub from '~icons/simple-icons/github'; @@ -30,6 +30,11 @@ import IconGoogle from '~icons/simple-icons/google'; const title = 'Profile'; +type SocialiteProvider = { + name: string; + label: string; +}; + const props = defineProps<{ user: User & { social_accounts?: Array<{ @@ -38,12 +43,11 @@ const props = defineProps<{ provider_avatar_url?: string; }>; }; - available_providers?: Array<{ - name: string; - label: string; - }>; + available_providers?: SocialiteProvider[]; }>(); +const page = usePage(); + const getInitials = (name: string) => { return name .split(' ') @@ -126,11 +130,52 @@ const getProviderIcon = (providerName: string) => { return providerIcons[providerName.toLowerCase()]; }; +const enabledProviders = computed(() => { + const auth = page.props.auth as { + socialite_providers?: SocialiteProvider[]; + }; + + return auth.socialite_providers ?? []; +}); + +const enabledProviderNames = computed( + () => new Set(enabledProviders.value.map((provider) => provider.name)), +); + +const isProviderEnabled = (providerName: string): boolean => { + return enabledProviderNames.value.has(providerName); +}; + +const socialiteProviders = computed(() => { + const configuredProviders = new Map( + (props.available_providers ?? []).map((provider) => [ + provider.name, + provider, + ]), + ); + const providers = new Map( + enabledProviders.value.map((provider) => [provider.name, provider]), + ); + + for (const account of props.user.social_accounts ?? []) { + if (!providers.has(account.provider)) { + providers.set( + account.provider, + configuredProviders.get(account.provider) ?? { + name: account.provider, + label: account.provider, + }, + ); + } + } + + return [...providers.values()]; +}); + const hasSocialiteProviders = computed(() => { return ( route().has('auth.socialite.redirect') && - props.available_providers && - props.available_providers.length > 0 + socialiteProviders.value.length > 0 ); }); @@ -232,9 +277,10 @@ const hasSocialiteProviders = computed(() => {
@@ -286,6 +332,7 @@ const hasSocialiteProviders = computed(() => { variant="destructive" size="sm" @click="initiateDisconnect(provider.name)" + :data-testid="`disconnect-socialite-${provider.name}`" :disabled=" isDisconnecting === provider.name " @@ -304,7 +351,7 @@ const hasSocialiteProviders = computed(() => { @@ -342,11 +390,16 @@ const hasSocialiteProviders = computed(() => { - diff --git a/tests/e2e/tests/profile/socialite.settings.spec.ts b/tests/e2e/tests/profile/socialite.settings.spec.ts new file mode 100644 index 0000000..d4d2685 --- /dev/null +++ b/tests/e2e/tests/profile/socialite.settings.spec.ts @@ -0,0 +1,51 @@ +import { expect, test } from '@e2e/fixtures'; + +test.describe('Profile Socialite Settings', () => { + test.describe.configure({ mode: 'serial' }); + + test('keeps a disabled connected provider available for disconnect', async ({ + page, + laravel, + credentials, + loginAs, + }) => { + const providerId = `e2e-disabled-google-${Date.now()}`; + + await laravel.query('UPDATE settings SET payload = ? WHERE name = ?', [ + '[]', + 'enabled_socialite_providers', + ]); + await laravel.query( + 'INSERT INTO social_accounts (user_id, provider, provider_id, last_login_at, created_at, updated_at) SELECT id, ?, ?, NOW(), NOW(), NOW() FROM users WHERE email = ?', + ['google', providerId, credentials.user.email], + ); + + try { + await loginAs(credentials.user); + await page.goto('/settings/profile'); + + await expect( + page.getByTestId('socialite-account-google'), + ).toBeVisible(); + await expect( + page.getByTestId('connect-socialite-google'), + ).not.toBeVisible(); + + await page.getByTestId('disconnect-socialite-google').click(); + await page.getByTestId('confirm-socialite-disconnect').click(); + + await expect( + page.getByTestId('socialite-account-google'), + ).not.toBeVisible(); + } finally { + await laravel.query( + 'DELETE FROM social_accounts WHERE provider = ? AND provider_id = ?', + ['google', providerId], + ); + await laravel.query( + 'UPDATE settings SET payload = ? WHERE name = ?', + ['[]', 'enabled_socialite_providers'], + ); + } + }); +}); From 327a5b966a1de378caba9908df09bd98d4b2d11b Mon Sep 17 00:00:00 2001 From: roble Date: Sat, 29 Aug 2026 17:28:10 +0100 Subject: [PATCH 2/3] fix: ensure original socialite provider settings are restored after test --- .../tests/profile/socialite.settings.spec.ts | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/e2e/tests/profile/socialite.settings.spec.ts b/tests/e2e/tests/profile/socialite.settings.spec.ts index d4d2685..5e89d74 100644 --- a/tests/e2e/tests/profile/socialite.settings.spec.ts +++ b/tests/e2e/tests/profile/socialite.settings.spec.ts @@ -10,17 +10,26 @@ test.describe('Profile Socialite Settings', () => { loginAs, }) => { const providerId = `e2e-disabled-google-${Date.now()}`; - - await laravel.query('UPDATE settings SET payload = ? WHERE name = ?', [ - '[]', - 'enabled_socialite_providers', - ]); - await laravel.query( - 'INSERT INTO social_accounts (user_id, provider, provider_id, last_login_at, created_at, updated_at) SELECT id, ?, ?, NOW(), NOW(), NOW() FROM users WHERE email = ?', - ['google', providerId, credentials.user.email], + const [socialiteProviderSetting] = await laravel.select( + 'SELECT payload FROM settings WHERE name = :name', + { name: 'enabled_socialite_providers' }, ); + const originalPayload = socialiteProviderSetting?.payload; + + if (typeof originalPayload !== 'string') { + throw new Error('Socialite provider setting was not found.'); + } try { + await laravel.query( + 'UPDATE settings SET payload = ? WHERE name = ?', + ['[]', 'enabled_socialite_providers'], + ); + await laravel.query( + 'INSERT INTO social_accounts (user_id, provider, provider_id, last_login_at, created_at, updated_at) SELECT id, ?, ?, NOW(), NOW(), NOW() FROM users WHERE email = ?', + ['google', providerId, credentials.user.email], + ); + await loginAs(credentials.user); await page.goto('/settings/profile'); @@ -44,7 +53,7 @@ test.describe('Profile Socialite Settings', () => { ); await laravel.query( 'UPDATE settings SET payload = ? WHERE name = ?', - ['[]', 'enabled_socialite_providers'], + [originalPayload, 'enabled_socialite_providers'], ); } }); From 51488f82da91ca5d1c8e2fb425bec6e02d0ce85d Mon Sep 17 00:00:00 2001 From: roble Date: Sat, 29 Aug 2026 17:32:58 +0100 Subject: [PATCH 3/3] fix: use CURRENT_TIMESTAMP instead of NOW() in social_accounts insert query --- tests/e2e/tests/profile/socialite.settings.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/tests/profile/socialite.settings.spec.ts b/tests/e2e/tests/profile/socialite.settings.spec.ts index 5e89d74..e456456 100644 --- a/tests/e2e/tests/profile/socialite.settings.spec.ts +++ b/tests/e2e/tests/profile/socialite.settings.spec.ts @@ -26,7 +26,7 @@ test.describe('Profile Socialite Settings', () => { ['[]', 'enabled_socialite_providers'], ); await laravel.query( - 'INSERT INTO social_accounts (user_id, provider, provider_id, last_login_at, created_at, updated_at) SELECT id, ?, ?, NOW(), NOW(), NOW() FROM users WHERE email = ?', + 'INSERT INTO social_accounts (user_id, provider, provider_id, last_login_at, created_at, updated_at) SELECT id, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP FROM users WHERE email = ?', ['google', providerId, credentials.user.email], );