Files
atproto/packages/bsky/tests/views/get-suggested-onboarding-users.test.ts
2026-03-23 18:10:16 +01:00

190 lines
4.7 KiB
TypeScript

import { once } from 'node:events'
import { Server, createServer } from 'node:http'
import { AddressInfo } from 'node:net'
import express, { Application } from 'express'
import {
AppBskyUnspeccedGetOnboardingSuggestedUsersSkeleton,
AtpAgent,
ids,
} from '@atproto/api'
import { SeedClient, TestNetwork } from '@atproto/dev-env'
type User = {
id: string
did: string
email: string
handle: string
password: string
displayName: string
description: string
selfLabels: undefined
}
function createUser(name: string): User {
return {
id: name,
// @ts-ignore overwritten below
did: undefined,
email: `${name}@test.com`,
handle: `${name}.test`,
password: `${name}-pass`,
displayName: name,
description: `hi im ${name}`,
selfLabels: undefined,
}
}
const users = {
suggestedUser: createUser('suggested-user'),
viewer: createUser('viewer'),
viewerBlocker: createUser('viewer-blocker'),
followedUser: createUser('followed-user'),
}
type Users = typeof users
async function seed(sc: SeedClient) {
const u = structuredClone(users)
for (const [key, user] of Object.entries(u)) {
await sc.createAccount(key, user)
u[key].did = sc.dids[key]
}
await sc.block(u.viewerBlocker.did, u.suggestedUser.did)
await sc.follow(u.viewer.did, u.followedUser.did)
await sc.network.processAll()
return { users: u }
}
describe('getSuggestedOnboardingUsers', () => {
let network: TestNetwork
let agent: AtpAgent
let sc: SeedClient
let seededUsers: Users
let mockServer: MockServer
beforeAll(async () => {
mockServer = new MockServer()
await mockServer.listen()
network = await TestNetwork.create({
dbPostgresSchema: 'bsky_tests_get_suggested_onboarding_users',
bsky: {
suggestionsUrl: mockServer.url,
suggestionsApiKey: 'test',
},
})
agent = network.bsky.getAgent()
sc = network.getSeedClient()
const result = await seed(sc)
seededUsers = result.users
await network.processAll()
})
afterAll(async () => {
await network.close()
await mockServer.stop()
})
describe(`basic handling`, () => {
beforeAll(() => {
mockServer.mockedDids.set('suggestedUser', seededUsers.suggestedUser.did)
})
afterAll(() => {
mockServer.mockedDids.delete('suggestedUser')
})
it(`returns users for non-blocking viewer`, async () => {
const { data } =
await agent.app.bsky.unspecced.getSuggestedOnboardingUsers(undefined, {
headers: await network.serviceHeaders(
seededUsers.viewer.did,
ids.AppBskyUnspeccedGetSuggestedOnboardingUsers,
),
})
const actor = data.actors.find(
(a) => a.did === seededUsers.suggestedUser.did,
)
expect(actor).toBeDefined()
})
it(`does not return user if blocked by viewer`, async () => {
const { data } =
await agent.app.bsky.unspecced.getSuggestedOnboardingUsers(undefined, {
headers: await network.serviceHeaders(
seededUsers.viewerBlocker.did,
ids.AppBskyUnspeccedGetSuggestedOnboardingUsers,
),
})
const actor = data.actors.find(
(a) => a.did === seededUsers.suggestedUser.did,
)
expect(actor).not.toBeDefined()
})
it(`does not return users that viewer already follows`, async () => {
mockServer.mockedDids.set('followedUser', seededUsers.followedUser.did)
const { data } =
await agent.app.bsky.unspecced.getSuggestedOnboardingUsers(undefined, {
headers: await network.serviceHeaders(
seededUsers.viewer.did,
ids.AppBskyUnspeccedGetSuggestedOnboardingUsers,
),
})
const actor = data.actors.find(
(a) => a.did === seededUsers.followedUser.did,
)
expect(actor).not.toBeDefined()
mockServer.mockedDids.delete('followedUser')
})
})
})
class MockServer {
app: Application
server: Server
mockedDids = new Map<string, string>()
constructor() {
this.app = this.createApp()
this.server = createServer(this.app)
}
async listen(port?: number) {
this.server.listen(port)
await once(this.server, 'listening')
}
async stop() {
this.server.close()
await once(this.server, 'close')
}
get url() {
const address = this.server.address() as AddressInfo
return `http://localhost:${address.port}`
}
private createApp() {
const app = express()
app.get(
'/xrpc/app.bsky.unspecced.getOnboardingSuggestedUsersSkeleton',
(req, res) => {
const skeleton: AppBskyUnspeccedGetOnboardingSuggestedUsersSkeleton.OutputSchema =
{
dids: Array.from(this.mockedDids.values()),
}
return res.json(skeleton)
},
)
return app
}
}