Skip to content
Draft
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
6 changes: 3 additions & 3 deletions app/pages/profile/[identity]/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ if (!profile.value || profileError.value?.statusCode === 404) {
})
}

const { user, pending: userPending } = useAtproto()
const { user } = useAtproto()
const isEditing = ref(false)
const displayNameInput = ref()
const descriptionInput = ref()
Expand Down Expand Up @@ -86,8 +86,8 @@ const showInviteSection = computed(() => {
profile.value.recordExists === false &&
status.value === 'success' &&
!likes.value?.records?.length &&
!userPending.value &&
user.value?.handle !== profile.value.handle
user.value &&
user.value.handle !== profile.value.handle
)
})

Expand Down
50 changes: 23 additions & 27 deletions test/nuxt/components/Package/Likes.spec.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import type { VueWrapper } from '@vue/test-utils'
import { mountSuspended, registerEndpoint } from '@nuxt/test-utils/runtime'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { ref } from 'vue'
import Likes from '~/components/Package/Likes.vue'
import { useAtproto } from '~/composables/atproto/useAtproto'

const { mockUseAtproto } = vi.hoisted(() => ({
mockUseAtproto: vi.fn(),
}))

vi.mock('~/composables/atproto/useAtproto', () => ({
useAtproto: mockUseAtproto,
}))
function createAtprotoUser(handle: string) {
return {
did: `did:plc:${handle}`,
handle,
pds: 'https://bsky.social',
}
}

describe('PackageLikes', () => {
let wrapper: VueWrapper | undefined

beforeEach(() => {
mockUseAtproto.mockReturnValue({
user: ref(null),
pending: ref(false),
logout: vi.fn(),
})
const { user } = useAtproto()
user.value = null
})

afterEach(() => {
Expand Down Expand Up @@ -75,26 +72,25 @@ describe('PackageLikes', () => {

it('keeps the top liked badge when a like response omits the rank', async () => {
let likeRequests = 0

mockUseAtproto.mockReturnValue({
user: ref({ handle: 'tester.test' }),
pending: ref(false),
logout: vi.fn(),
})
const { user } = useAtproto()
user.value = createAtprotoUser('tester.test')

registerEndpoint('/api/social/likes/svelte', () => ({
totalLikes: 42,
userHasLiked: false,
topLikedRank: 3,
}))
registerEndpoint('/api/social/like', () => {
likeRequests++

return {
totalLikes: 43,
userHasLiked: true,
topLikedRank: null,
}
registerEndpoint('/api/social/like', {
method: 'POST',
handler: () => {
likeRequests++

return {
totalLikes: 43,
userHasLiked: true,
topLikedRank: null,
}
},
})

wrapper = await mountSuspended(Likes, {
Expand Down
37 changes: 18 additions & 19 deletions test/nuxt/components/ProfileInviteSection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { mockNuxtImport, mountSuspended, registerEndpoint } from '@nuxt/test-utils/runtime'
import { describe, expect, it, vi, beforeEach } from 'vitest'
import { useAtproto } from '~/composables/atproto/useAtproto'

const { mockUseAtproto, mockUseProfileLikes } = vi.hoisted(() => ({
mockUseAtproto: vi.fn(),
const { mockUseProfileLikes } = vi.hoisted(() => ({
mockUseProfileLikes: vi.fn(),
}))

mockNuxtImport('useAtproto', () => mockUseAtproto)
mockNuxtImport('useProfileLikes', () => mockUseProfileLikes)

import ProfilePage from '~/pages/profile/[identity]/index.vue'

function createAtprotoUser(handle: string) {
return {
did: `did:plc:${handle}`,
handle,
pds: 'https://bsky.social',
}
}

registerEndpoint('/api/social/profile/test-handle', () => ({
displayName: 'Test User',
description: '',
Expand All @@ -21,16 +28,14 @@ registerEndpoint('/api/social/profile/test-handle', () => ({

describe('Profile invite section', () => {
beforeEach(() => {
mockUseAtproto.mockReset()
const { user } = useAtproto()
user.value = null
mockUseProfileLikes.mockReset()
})

it('does not show invite section while auth is still loading', async () => {
mockUseAtproto.mockReturnValue({
user: ref(null),
pending: ref(true),
logout: vi.fn(),
})
const { user } = useAtproto()
user.value = undefined

mockUseProfileLikes.mockReturnValue({
data: ref({ records: [] }),
Expand All @@ -45,11 +50,8 @@ describe('Profile invite section', () => {
})

it('shows invite section after auth resolves for non-owner', async () => {
mockUseAtproto.mockReturnValue({
user: ref({ handle: 'other-user' }),
pending: ref(false),
logout: vi.fn(),
})
const { user } = useAtproto()
user.value = createAtprotoUser('other-user')

mockUseProfileLikes.mockReturnValue({
data: ref({ records: [] }),
Expand All @@ -64,11 +66,8 @@ describe('Profile invite section', () => {
})

it('does not show invite section for profile owner', async () => {
mockUseAtproto.mockReturnValue({
user: ref({ handle: 'test-handle' }),
pending: ref(false),
logout: vi.fn(),
})
const { user } = useAtproto()
user.value = createAtprotoUser('test-handle')

mockUseProfileLikes.mockReturnValue({
data: ref({ records: [] }),
Expand Down
34 changes: 21 additions & 13 deletions test/nuxt/composables/use-command-palette-commands.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { computed, defineComponent, h, ref, watchEffect, type Ref } from 'vue'
import type { RouteLocationRaw } from 'vue-router'
import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime'
import { mockNuxtImport, mountSuspended, registerEndpoint } from '@nuxt/test-utils/runtime'
import { useAtproto } from '~/composables/atproto/useAtproto'
import { downloadPackageTarball } from '~/utils/package-download'
import type {
CommandPaletteCommand,
Expand All @@ -23,9 +24,15 @@ const mockConnectorState = ref<{
npmUser: null,
})

const mockAtprotoHandle = ref<string | null>(null)
const mockDisconnectNpm = vi.fn()
const mockLogout = vi.fn(async () => {})

function createAtprotoUser(handle: string) {
return {
did: `did:plc:${handle}`,
handle,
pds: 'https://bsky.social',
}
}

mockNuxtImport('useConnector', () => {
return () => ({
Expand All @@ -35,13 +42,6 @@ mockNuxtImport('useConnector', () => {
})
})

mockNuxtImport('useAtproto', () => {
return () => ({
user: computed(() => (mockAtprotoHandle.value ? { handle: mockAtprotoHandle.value } : null)),
logout: mockLogout,
})
})

async function captureCommandPalette(options?: {
route?: string
query?: string
Expand All @@ -62,7 +62,8 @@ async function captureCommandPalette(options?: {
connected: !!options?.npmUser,
npmUser: options?.npmUser ?? null,
}
mockAtprotoHandle.value = options?.atprotoHandle ?? null
const { user } = useAtproto()
user.value = options?.atprotoHandle ? createAtprotoUser(options.atprotoHandle) : null

const WrapperComponent = defineComponent({
setup() {
Expand Down Expand Up @@ -122,7 +123,8 @@ afterEach(() => {
connected: false,
npmUser: null,
}
mockAtprotoHandle.value = null
const { user } = useAtproto()
user.value = null
vi.clearAllMocks()
})

Expand Down Expand Up @@ -312,6 +314,12 @@ describe('useCommandPaletteCommands', () => {
})

it('adds atproto account commands and disconnect support when a profile is connected', async () => {
const deleteSession = vi.fn(() => null)
registerEndpoint('/api/auth/session', {
method: 'DELETE',
handler: deleteSession,
})

const { wrapper, flatCommands } = await captureCommandPalette({
route: '/profile/alice.bsky.social',
atprotoHandle: 'alice.bsky.social',
Expand All @@ -324,7 +332,7 @@ describe('useCommandPaletteCommands', () => {

await flatCommands.value.find(command => command.id === 'atproto-disconnect')?.action?.()

expect(mockLogout).toHaveBeenCalledTimes(1)
expect(deleteSession).toHaveBeenCalledTimes(1)
expect(commandPalette.isOpen.value).toBe(false)

wrapper.unmount()
Expand Down
Loading