Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit test for user settings menu #872

Merged
merged 1 commit into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions frontend/src/components/__tests__/user_settings/Menu.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { describe, it, expect, beforeEach, vi, afterEach, afterAll } from 'vitest'
import { mount } from '@vue/test-utils'
import Menu from '../../user_settings/Menu.vue'

let userStoreData = {
username: 'test',
nickname: 'testn',
email: '[email protected]',
avatar: 'test_avatar.com'
}
vi.mock('../../../stores/UserStore', () => ({
default: () => (userStoreData)
}))

describe('Menu', () => {
let wrapper

beforeEach(() => {
vi.clearAllMocks()
wrapper = mount(Menu)
})

describe('Initial State', () => {
it('mounts with correct default props', () => {
expect(wrapper.exists()).toBe(true)
expect(wrapper.vm.hasSave).toBe(true)
})
})

describe('template render with email', () => {
it('renders access token navbar', () => {
const link = wrapper.find('a[href="/settings/access-token"]')
expect(link.exists()).toBe(true);
})
it('renders ssh key navbar', () => {
const link = wrapper.find('a[href="/settings/ssh-keys"]')
expect(link.exists()).toBe(true);
})
})

describe('template render without email', () => {
beforeEach(() => {
userStoreData = { username: 'test', nickname: 'testn', avatar: 'test_avatar.com' };
wrapper = mount(Menu)
})
it('renders access token navbar', async () => {
const link = wrapper.find('a[href="/settings/access-token"]')
expect(link.exists()).toBe(false);
})
it('renders ssh key navbar', () => {
const link = wrapper.find('a[href="/settings/ssh-keys"]')
expect(link.exists()).toBe(false);
})
})

describe('click on avatar to jump with saved true', () => {
it('jumps to user profile', async () => {
const avatarDiv = wrapper.find('#user_settings_avatar_div')
await avatarDiv.trigger('click')
expect(window.location.href).toBe(`/profile/${userStoreData.username}`)
})
})

describe('click on avatar to jump with saved false', () => {
beforeEach(() => {
wrapper = mount(Menu, {
props: {
hasSave: false
}
})
})

it('pops up confirm dialog', async () => {
const avatarDiv = wrapper.find('#user_settings_avatar_div')
await avatarDiv.trigger('click')
expect(wrapper.vm.showDialog).toBe(true)
})

it('hide dialog after click on cancel', async () => {
const avatarDiv = wrapper.find('#user_settings_avatar_div')
await avatarDiv.trigger('click')
const cancelBtn = wrapper.find('#user_settings_dialog_cancel')
await cancelBtn.trigger('click')
expect(wrapper.vm.showDialog).toBe(false)
})

it('jumps to user profile after click on confirm', async () => {
const avatarDiv = wrapper.find('#user_settings_avatar_div')
await avatarDiv.trigger('click')
const confirmBtn = wrapper.find('#user_settings_dialog_confirm')
await confirmBtn.trigger('click')
expect(window.location.href).toBe(`/profile/${userStoreData.username}`)
})
})
})
157 changes: 92 additions & 65 deletions frontend/src/components/user_settings/Menu.vue
Original file line number Diff line number Diff line change
@@ -1,76 +1,103 @@
<template>
<div class="pt-6">
<div class="w-[294px] rounded-md mx-[24px] md:w-full md:mx-0">
<div @click="clickProfile" class="flex p-[16px] cursor-pointer">
<el-avatar :size="60" :src="userStore.avatar"> </el-avatar>
<div class="ml-[10px]">
<div class="text-lg leading-[28px] font-semibold">
{{ userStore.nickname || userStore.username }}
</div>
<div class="text-md text-gray-500 leading-[24px] font-light">@{{ userStore.username }}</div>
<div class="pt-6">
<div class="w-[294px] rounded-md mx-[24px] md:w-full md:mx-0">
<div
@click="clickProfile"
class="flex p-[16px] cursor-pointer"
id="user_settings_avatar_div">
<el-avatar
:size="60"
:src="userStore.avatar">
</el-avatar>
<div class="ml-[10px]">
<div class="text-lg leading-[28px] font-semibold">
{{ userStore.nickname || userStore.username }}
</div>
<div class="text-md text-gray-500 leading-[24px] font-light">
@{{ userStore.username }}
</div>
</div>
<div class="flex flex-col md:hidden">
<!-- profile -->
<a href="/settings/profile"
class="p-[16px] hover:bg-gray-50 border-gray-200 text-md text-gray-500 leading-[24px] cursor-pointer"
:class="menuClass('/settings/profile')"
>
{{ $t('profile.accountSetting')}}
</a>

<!-- access token -->
<a v-if="hasEmail"
href="/settings/access-token"
class="p-[16px] hover:bg-gray-50 border-gray-200 text-md text-gray-500 leading-[24px] cursor-pointer"
:class="menuClass('/settings/access-token')"
>
{{ $t('profile.menu.gitToken')}}
</a>
</div>
<div class="flex flex-col md:hidden">
<!-- profile -->
<a
href="/settings/profile"
class="p-[16px] hover:bg-gray-50 border-gray-200 text-md text-gray-500 leading-[24px] cursor-pointer"
:class="menuClass('/settings/profile')">
{{ $t('profile.accountSetting') }}
</a>

<!-- ssh key -->
<a v-if="hasEmail"
href="/settings/ssh-keys"
class="p-[16px] hover:bg-gray-50 border-gray-200 text-md text-gray-500 leading-[24px] cursor-pointer"
:class="menuClass('/settings/ssh-keys')"
>
{{ $t('profile.menu.sshKey')}}
</a>
<!-- access token -->
<a
v-if="hasEmail"
href="/settings/access-token"
class="p-[16px] hover:bg-gray-50 border-gray-200 text-md text-gray-500 leading-[24px] cursor-pointer"
:class="menuClass('/settings/access-token')">
{{ $t('profile.menu.gitToken') }}
</a>

</div>
<!-- mobile tabs -->
<div class="profileTabs hidden md:block">
<el-tabs v-model="activeTab" @tabClick="handleTabClick">
<el-tab-pane :label="$t('profile.accountSetting')" name="/settings/profile"></el-tab-pane>
<el-tab-pane v-if="hasEmail" :label="$t('profile.menu.gitToken')" name="/settings/access-token"></el-tab-pane>
<el-tab-pane v-if="hasEmail" :label="$t('profile.menu.starshipAccessToken')" name="/settings/starship-access-token"></el-tab-pane>
<el-tab-pane v-if="hasEmail" :label="$t('profile.menu.syncAccessToken')" name="/settings/sync-access-token"></el-tab-pane>
<el-tab-pane v-if="hasEmail" :label="$t('profile.menu.sshKey')" name="/settings/ssh-keys"></el-tab-pane>
<!-- ssh key -->
<a
v-if="hasEmail"
href="/settings/ssh-keys"
class="p-[16px] hover:bg-gray-50 border-gray-200 text-md text-gray-500 leading-[24px] cursor-pointer"
:class="menuClass('/settings/ssh-keys')">
{{ $t('profile.menu.sshKey') }}
</a>
</div>
<!-- mobile tabs -->
<div class="profileTabs hidden md:block">
<el-tabs
v-model="activeTab"
@tabClick="handleTabClick">
<el-tab-pane
:label="$t('profile.accountSetting')"
name="/settings/profile"></el-tab-pane>
<el-tab-pane
v-if="hasEmail"
:label="$t('profile.menu.gitToken')"
name="/settings/access-token"></el-tab-pane>
<el-tab-pane
v-if="hasEmail"
:label="$t('profile.menu.sshKey')"
name="/settings/ssh-keys"></el-tab-pane>
</el-tabs>
</div>

</div>
</div>
<el-dialog
v-model="showDialog"
width="350"
:style="{ borderRadius: '10px' }"
>
<template #header>
{{ $t('profile.menu.warningTip') }}
</template>
<div class="flex justify-center flex-col m-auto w-full relative">
{{ $t('profile.menu.warningTipDesc') }}
</div>

<el-dialog
v-model="showDialog"
width="350"
:style="{ borderRadius: '10px' }">
<template #header>
{{ $t('profile.menu.warningTip') }}
</template>
<div class="flex justify-center flex-col m-auto w-full relative">
{{ $t('profile.menu.warningTipDesc') }}
</div>
<template #footer>
<div class="dialog-footer flex justify-between">
<el-button
id="user_settings_dialog_cancel"
class="flex-1 mr-3 text-gray-700"
size="large"
@click="showDialog = false"
>{{ $t('organization.members.cancel') }}</el-button
>
<el-button
id="user_settings_dialog_confirm"
class="flex-1"
size="large"
color="#3250BD"
type="primary"
:loading="loading"
@click="handleConfirm">
{{ $t('organization.members.confirm') }}
</el-button>
</div>
<template #footer>
<div class="dialog-footer flex justify-between">
<el-button class="flex-1 mr-3 text-gray-700" size="large" @click="showDialog = false">{{ $t('organization.members.cancel') }}</el-button>
<el-button class="flex-1" size="large" color="#3250BD" type="primary" :loading="loading" @click="handleConfirm">
{{ $t('organization.members.confirm') }}
</el-button>
</div>
</template>
</el-dialog>
</template>
</el-dialog>
</template>

<script setup>
Expand Down Expand Up @@ -116,7 +143,7 @@
}
</script>
<style>
.profileTabs .el-tabs__nav-scroll {
.profileTabs .el-tabs__nav-scroll {
@media screen and (max-width: 768px) {
padding-left: 0px !important;
}
Expand Down
Loading