Skip to content
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
2 changes: 1 addition & 1 deletion app/components/AppFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const showModal = () => modalRef.value?.showModal?.()
>
<div>
<p class="font-mono text-balance m-0 hidden sm:block">{{ $t('tagline') }}</p>
<BuildEnvironment v-if="!isHome" footer />
</div>
<!-- Desktop: Show all links. Mobile: Links are in MobileMenu -->
<div class="hidden sm:flex items-center gap-6 min-h-11 text-xs">
Expand Down Expand Up @@ -105,6 +104,7 @@ const showModal = () => modalRef.value?.showModal?.()
</Modal>
</div>
</div>
<BuildEnvironment v-if="!isHome" footer />
<p class="text-xs text-fg-muted text-center sm:text-start m-0">
<span class="sm:hidden">{{ $t('non_affiliation_disclaimer') }}</span>
<span class="hidden sm:inline">{{ $t('trademark_disclaimer') }}</span>
Expand Down
10 changes: 7 additions & 3 deletions app/components/BuildEnvironment.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<script setup lang="ts">
defineProps<{
import type { BuildInfo } from '#shared/types'

const { footer = false, buildInfo: buildInfoProp } = defineProps<{
footer?: boolean
buildInfo?: BuildInfo
}>()

const { locale } = useI18n()
const buildInfo = useAppConfig().buildInfo
const appConfig = useAppConfig()
const buildInfo = computed(() => buildInfoProp || appConfig.buildInfo)
</script>

<template>
<div
class="font-mono text-xs text-fg-muted flex items-center gap-2 motion-safe:animate-fade-in motion-safe:animate-fill-both"
:class="footer ? 'mt-4 justify-start' : 'mb-8 justify-center'"
:class="footer ? 'my-1 justify-center sm:justify-start' : 'mb-8 justify-center'"
style="animation-delay: 0.05s"
>
<i18n-t keypath="built_at" scope="global">
Expand Down
45 changes: 30 additions & 15 deletions modules/build-env.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BuildInfo } from '../shared/types'
import type { BuildInfo, EnvType } from '../shared/types'
import { createResolver, defineNuxtModule } from 'nuxt/kit'
import { isCI } from 'std-env'
import { getEnv, getFileLastUpdated, version } from '../config/env'
Expand All @@ -10,22 +10,37 @@ export default defineNuxtModule({
name: 'npmx:build-env',
},
async setup(_options, nuxt) {
const [{ env, commit, shortCommit, branch }, privacyPolicyDate] = await Promise.all([
getEnv(nuxt.options.dev),
getFileLastUpdated('app/pages/privacy.vue'),
])

let env: EnvType = 'dev'
nuxt.options.appConfig = nuxt.options.appConfig || {}
nuxt.options.appConfig.env = env
nuxt.options.appConfig.buildInfo = {
version,
time: +Date.now(),
commit,
shortCommit,
branch,
env,
privacyPolicyDate,
} satisfies BuildInfo
if (process.env.TEST) {
const time = new Date()
nuxt.options.appConfig.buildInfo = {
env,
version: '0.0.0',
commit: '704987bba88909f3782d792c224bde989569acb9',
shortCommit: '704987b',
branch: 'xxx',
time: time.getTime(),
privacyPolicyDate: time.toISOString(),
} satisfies BuildInfo
} else {
const [{ env: useEnv, commit, shortCommit, branch }, privacyPolicyDate] = await Promise.all([
getEnv(nuxt.options.dev),
getFileLastUpdated('app/pages/privacy.vue'),
])
env = useEnv
nuxt.options.appConfig.env = useEnv
Comment on lines +16 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for TEST environment variable configuration
rg -n 'process\.env\.TEST|TEST\s*=' --type ts --type js --type json

Repository: npmx-dev/npmx.dev

Length of output: 112


🏁 Script executed:

# Check if std-env is in dependencies and available
if [ -f package.json ]; then
  echo "=== Checking package.json for std-env ==="
  rg '"std-env"' package.json
  echo ""
fi

# Look for vitest configuration
echo "=== Looking for vitest config files ==="
fd -e 'vitest\.config' -e 'vite\.config' 2>/dev/null | head -20

Repository: npmx-dev/npmx.dev

Length of output: 168


🏁 Script executed:

# Search for vitest setup files and test configuration
rg -n 'TEST|test.*env' --type ts --type js vitest.config 2>/dev/null || echo "No vitest.config found"

Repository: npmx-dev/npmx.dev

Length of output: 83


🏁 Script executed:

# Check if std-env is imported anywhere in the codebase
echo "=== Checking imports of std-env ==="
rg "from\s+['\"]std-env" --type ts --type js

echo ""
echo "=== Checking process.env.TEST usage across codebase ==="
rg "process\.env\.TEST" --type ts --type js -C 2

Repository: npmx-dev/npmx.dev

Length of output: 738


🏁 Script executed:

# Check NODE_ENV usage in test context
echo "=== Checking NODE_ENV usage ==="
rg "NODE_ENV\s*===\s*['\"]test" --type ts --type js

echo ""
echo "=== Checking test scripts in package.json ==="
if [ -f package.json ]; then
  jq -r '.scripts | to_entries[] | select(.key | contains("test")) | "\(.key): \(.value)"' package.json 2>/dev/null || grep -A 5 '"test"' package.json
fi

Repository: npmx-dev/npmx.dev

Length of output: 615


Use isTest from std-env for consistent test-mode detection.

The process.env.TEST flag is not explicitly wired in this repository's test configuration. std-env (v3.10.0) is already available and isTest is already imported and used in modules/lunaria.ts, making this the standard approach. Replace process.env.TEST with isTest to ensure test-mode logic executes reliably.

-import { isCI } from 'std-env'
+import { isCI, isTest } from 'std-env'
...
-    if (process.env.TEST) {
+    if (isTest) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (process.env.TEST) {
const time = new Date()
nuxt.options.appConfig.buildInfo = {
env,
version: '0.0.0',
commit: '704987bba88909f3782d792c224bde989569acb9',
shortCommit: '704987b',
branch: 'xxx',
time: time.getTime(),
privacyPolicyDate: time.toISOString(),
} satisfies BuildInfo
} else {
const [{ env: useEnv, commit, shortCommit, branch }, privacyPolicyDate] = await Promise.all([
getEnv(nuxt.options.dev),
getFileLastUpdated('app/pages/privacy.vue'),
])
env = useEnv
nuxt.options.appConfig.env = useEnv
if (isTest) {
const time = new Date()
nuxt.options.appConfig.buildInfo = {
env,
version: '0.0.0',
commit: '704987bba88909f3782d792c224bde989569acb9',
shortCommit: '704987b',
branch: 'xxx',
time: time.getTime(),
privacyPolicyDate: time.toISOString(),
} satisfies BuildInfo
} else {
const [{ env: useEnv, commit, shortCommit, branch }, privacyPolicyDate] = await Promise.all([
getEnv(nuxt.options.dev),
getFileLastUpdated('app/pages/privacy.vue'),
])
env = useEnv
nuxt.options.appConfig.env = useEnv

nuxt.options.appConfig.buildInfo = {
version,
time: +Date.now(),
commit,
shortCommit,
branch,
env,
privacyPolicyDate,
} satisfies BuildInfo
}

nuxt.options.nitro.publicAssets = nuxt.options.nitro.publicAssets || []
if (env === 'dev') nuxt.options.nitro.publicAssets.unshift({ dir: resolve('../public-dev') })
Expand Down
4 changes: 3 additions & 1 deletion shared/types/env.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
export type EnvType = 'dev' | 'preview' | 'canary' | 'release'

export interface BuildInfo {
version: string
commit: string
shortCommit: string
time: number
branch: string
env: 'preview' | 'canary' | 'dev' | 'release'
env: EnvType
privacyPolicyDate: string
}
35 changes: 35 additions & 0 deletions test/nuxt/components/AppFooter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { describe, expect, it } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import AppFooter from '~/components/AppFooter.vue'

/* check nuxt module at modules/build-env.ts */
describe('AppFooter', () => {
it('BuildEnvironment is properly displayed at settings', async () => {
const buildInfo = useAppConfig().buildInfo
const component = await mountSuspended(AppFooter, {
route: '/settings',
})

const envSpan = component.find('span.tracking-wider')
expect(envSpan.exists()).toBe(true)
expect(envSpan.text()).toBe(buildInfo.env)
const commitLink = component.find(`a[href$="/commit/${buildInfo.commit}"]`)
expect(commitLink.exists()).toBe(true)
const tagLink = component.find(`a[href$="/tag/v${buildInfo.version}"]`)
expect(tagLink.exists()).toBe(false)
})

it('BuildEnvironment is hidden at home', async () => {
const buildInfo = useAppConfig().buildInfo
const component = await mountSuspended(AppFooter, {
route: '/',
})

const envSpan = component.find('span.tracking-wider')
expect(envSpan.exists()).toBe(false)
const commitLink = component.find(`a[href$="/commit/${buildInfo.commit}"]`)
expect(commitLink.exists()).toBe(false)
const tagLink = component.find(`a[href$="/tag/v${buildInfo.version}"]`)
expect(tagLink.exists()).toBe(false)
})
})
58 changes: 58 additions & 0 deletions test/nuxt/components/BuildEnvironment.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { BuildInfo } from '#shared/types'
import { describe, expect, it } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import BuildEnvironment from '~/components/BuildEnvironment.vue'

describe('BuildEnvironment', () => {
it('renders dev environment correctly', async () => {
const buildInfo: BuildInfo = {
env: 'dev',
version: '1.2.3',
time: 1234567890,
commit: 'abcdef',
shortCommit: 'abc',
branch: 'main',
privacyPolicyDate: new Date().toISOString(),
}
const component = await mountSuspended(BuildEnvironment, {
props: {
buildInfo,
},
})

// In dev mode, it shows env name, not version link
const envSpan = component.find('span.tracking-wider')
expect(envSpan.exists()).toBe(true)
expect(envSpan.text()).toBe(buildInfo.env)
const commitLink = component.find(`a[href$="/commit/${buildInfo.commit}"]`)
expect(commitLink.exists()).toBe(true)
const tagLink = component.find(`a[href$="/tag/v${buildInfo.version}"]`)
expect(tagLink.exists()).toBe(false)
})

it('renders release environment correctly', async () => {
const buildInfo: BuildInfo = {
env: 'release',
version: '1.2.3',
time: 1234567890,
commit: 'abcdef',
shortCommit: 'abc',
branch: 'release',
privacyPolicyDate: new Date().toISOString(),
}

const component = await mountSuspended(BuildEnvironment, {
props: {
buildInfo,
},
})

// In release mode, it shows tag version link, not env name
const envSpan = component.find('span.tracking-wider')
expect(envSpan.exists()).toBe(false)
const commitLink = component.find(`a[href$="/commit/${buildInfo.commit}"]`)
expect(commitLink.exists()).toBe(false)
const tagLink = component.find(`a[href$="/tag/v${buildInfo.version}"]`)
expect(tagLink.exists()).toBe(true)
})
})
Loading