diff --git a/modules/runtime/server/cache.ts b/modules/runtime/server/cache.ts index d3117dd510..5741e4551b 100644 --- a/modules/runtime/server/cache.ts +++ b/modules/runtime/server/cache.ts @@ -195,6 +195,44 @@ function getMockForUrl(url: string): MockResult | null { return { data: null } } + // npm attestations API - return empty attestations (provenance not needed in tests) + if (host === 'registry.npmjs.org' && pathname.startsWith('/-/npm/v1/attestations/')) { + return { data: { attestations: [] } } + } + + // Constellation API - return empty results for link queries + if (host === 'constellation.microcosm.blue') { + if (pathname === '/links/distinct-dids') { + return { data: { total: 0, linking_dids: [], cursor: undefined } } + } + if (pathname === '/links/all') { + return { data: { links: {} } } + } + if (pathname === '/xrpc/blue.microcosm.links.getBacklinks') { + return { data: { total: 0, records: [], cursor: undefined } } + } + return { data: null } + } + + // UNGH (GitHub proxy) - return mock repo metadata + if (host === 'ungh.cc') { + const repoMatch = pathname.match(/^\/repos\/([^/]+)\/([^/]+)$/) + if (repoMatch?.[1] && repoMatch?.[2]) { + return { + data: { + repo: { + description: `${repoMatch[1]}/${repoMatch[2]} - mock repo description`, + stars: 1000, + forks: 100, + watchers: 50, + defaultBranch: 'main', + }, + }, + } + } + return { data: null } + } + // GitHub API - handled via fixtures, return null to use fixture system // Note: The actual fixture loading is handled in fetchFromFixtures via special case if (host === 'api.github.com') { @@ -426,6 +464,19 @@ async function handleGitHubApi( return { data: [] } } + // Commits endpoint: /repos/{owner}/{repo}/commits + const commitsMatch = pathname.match(/^\/repos\/([^/]+)\/([^/]+)\/commits$/) + if (commitsMatch) { + // Return a single-item array; fetchPageCount will use body.length when no Link header + return { data: [{ sha: 'mock-commit' }] } + } + + // Search endpoint: /search/issues, /search/commits, etc. + const searchMatch = pathname.match(/^\/search\/(.+)$/) + if (searchMatch) { + return { data: { total_count: 0, incomplete_results: false, items: [] } } + } + // Other GitHub API endpoints can be added here as needed return null } diff --git a/nuxt.config.ts b/nuxt.config.ts index dc1e0b4fd1..2a3629aa3c 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -1,6 +1,6 @@ import process from 'node:process' import { currentLocales } from './config/i18n' -import { isCI, provider } from 'std-env' +import { isCI, isTest, provider } from 'std-env' export default defineNuxtConfig({ modules: [ @@ -216,6 +216,9 @@ export default defineNuxtConfig({ include: ['../test/unit/server/**/*.ts'], }, }, + replace: { + 'import.meta.test': isTest, + }, }, fonts: { diff --git a/server/utils/atproto/oauth.ts b/server/utils/atproto/oauth.ts index e82ce85e46..c5c3380dc6 100644 --- a/server/utils/atproto/oauth.ts +++ b/server/utils/atproto/oauth.ts @@ -19,20 +19,18 @@ export const handleResolver = new AtprotoDohHandleResolver({ }) export function getOauthClientMetadata() { - const dev = import.meta.dev + const redirect_uri = `${clientUri}/api/auth/atproto` - const client_uri = clientUri - const redirect_uri = `${client_uri}/api/auth/atproto` - - const client_id = dev - ? `http://localhost?redirect_uri=${encodeURIComponent(redirect_uri)}&scope=${encodeURIComponent(scope)}` - : `${client_uri}/oauth-client-metadata.json` + const client_id = + import.meta.dev || import.meta.test + ? `http://localhost?redirect_uri=${encodeURIComponent(redirect_uri)}&scope=${encodeURIComponent(scope)}` + : `${clientUri}/oauth-client-metadata.json` // If anything changes here, please make sure to also update /shared/schemas/oauth.ts to match return parse(OAuthMetadataSchema, { client_name: 'npmx.dev', client_id, - client_uri, + client_uri: clientUri, scope, redirect_uris: [redirect_uri] as [string, ...string[]], grant_types: ['authorization_code', 'refresh_token'], diff --git a/test/e2e/og-image.spec.ts-snapshots/og-image-for--package-nuxt-v-3-20-2.png b/test/e2e/og-image.spec.ts-snapshots/og-image-for--package-nuxt-v-3-20-2.png index dd02dc3aeb..a8798d49bd 100644 Binary files a/test/e2e/og-image.spec.ts-snapshots/og-image-for--package-nuxt-v-3-20-2.png and b/test/e2e/og-image.spec.ts-snapshots/og-image-for--package-nuxt-v-3-20-2.png differ diff --git a/test/fixtures/mock-routes.cjs b/test/fixtures/mock-routes.cjs index d97915bf73..bd5527246b 100644 --- a/test/fixtures/mock-routes.cjs +++ b/test/fixtures/mock-routes.cjs @@ -124,6 +124,11 @@ function matchNpmRegistry(urlString) { return json({ error: 'Not found' }, 404) } + // Attestations endpoint - return empty attestations + if (pathname.startsWith('/-/npm/v1/attestations/')) { + return json({ attestations: [] }) + } + // Packument if (!pathname.startsWith('/-/')) { let packageName = pathname.slice(1) @@ -440,6 +445,52 @@ function matchGravatarApi(_urlString) { return { status: 404, contentType: 'text/plain', body: 'Not found' } } +/** + * @param {string} urlString + * @returns {MockResponse | null} + */ +function matchUnghApi(urlString) { + const url = new URL(urlString) + + const repoMatch = url.pathname.match(/^\/repos\/([^/]+)\/([^/]+)$/) + if (repoMatch && repoMatch[1] && repoMatch[2]) { + return json({ + repo: { + description: `${repoMatch[1]}/${repoMatch[2]} - mock repo description`, + stars: 1000, + forks: 100, + watchers: 50, + defaultBranch: 'main', + }, + }) + } + + return json(null) +} + +/** + * @param {string} urlString + * @returns {MockResponse | null} + */ +function matchConstellationApi(urlString) { + const url = new URL(urlString) + + if (url.pathname === '/links/distinct-dids') { + return json({ total: 0, linking_dids: [], cursor: undefined }) + } + + if (url.pathname === '/links/all') { + return json({ links: {} }) + } + + if (url.pathname === '/xrpc/blue.microcosm.links.getBacklinks') { + return json({ total: 0, records: [], cursor: undefined }) + } + + // Unknown constellation endpoint - return empty + return json(null) +} + /** * @param {string} urlString * @returns {MockResponse | null} @@ -454,6 +505,18 @@ function matchGitHubApi(urlString) { return json(fixture || []) } + // Commits endpoint + const commitsMatch = pathname.match(/^\/repos\/([^/]+)\/([^/]+)\/commits$/) + if (commitsMatch) { + return json([{ sha: 'mock-commit' }]) + } + + // Search endpoint (issues, commits, etc.) + const searchMatch = pathname.match(/^\/search\/(.+)$/) + if (searchMatch) { + return json({ total_count: 0, incomplete_results: false, items: [] }) + } + return null } @@ -480,6 +543,12 @@ const routes = [ }, { name: 'Gravatar API', pattern: 'https://www.gravatar.com/**', match: matchGravatarApi }, { name: 'GitHub API', pattern: 'https://api.github.com/**', match: matchGitHubApi }, + { name: 'UNGH API', pattern: 'https://ungh.cc/**', match: matchUnghApi }, + { + name: 'Constellation API', + pattern: 'https://constellation.microcosm.blue/**', + match: matchConstellationApi, + }, ] /**