|
|
@@ -0,0 +1,165 @@
|
|
|
+import test from 'node:test'
|
|
|
+import assert from 'node:assert/strict'
|
|
|
+import fs from 'node:fs'
|
|
|
+import path from 'node:path'
|
|
|
+import vm from 'node:vm'
|
|
|
+
|
|
|
+function scriptSetup (file) {
|
|
|
+ return fs.readFileSync(path.resolve(file), 'utf8')
|
|
|
+ .match(/<script setup[^>]*>([\s\S]*?)<\/script>/)[1]
|
|
|
+ .replace(/^\s*import\s+.*$/gm, '')
|
|
|
+}
|
|
|
+
|
|
|
+function mountActivityCard () {
|
|
|
+ const navigations = []
|
|
|
+ const context = {
|
|
|
+ ref: value => ({ value }),
|
|
|
+ computed: getter => ({ get value () { return getter() } }),
|
|
|
+ defineProps: () => ({ item: { id: 'activity-1' }, index: 0 }),
|
|
|
+ useUserStore: () => ({}),
|
|
|
+ useGlobalShare: () => ({ isLogin: () => false }),
|
|
|
+ uni: { navigateTo: options => navigations.push(options) }
|
|
|
+ }
|
|
|
+ vm.runInNewContext(
|
|
|
+ scriptSetup('components/pages/nonprofitActivety/index.vue') +
|
|
|
+ '\nglobalThis.__card = { handleDetail }',
|
|
|
+ context
|
|
|
+ )
|
|
|
+ return { card: context.__card, navigations }
|
|
|
+}
|
|
|
+
|
|
|
+function mountActivityDetail ({ loggedIn = false, storage = {} } = {}) {
|
|
|
+ const lifecycle = {}
|
|
|
+ const navigations = []
|
|
|
+ const apiRequests = []
|
|
|
+ const modals = []
|
|
|
+ let loginChecks = 0
|
|
|
+ const userStore = {
|
|
|
+ token: '',
|
|
|
+ openLoginModal () {}
|
|
|
+ }
|
|
|
+ const context = {
|
|
|
+ ref: value => ({ value }),
|
|
|
+ reactive: value => value,
|
|
|
+ onMounted: () => {},
|
|
|
+ nextTick: callback => callback(),
|
|
|
+ watch: (getter, callback) => { lifecycle.watchToken = callback },
|
|
|
+ onLoad: callback => { lifecycle.load = callback },
|
|
|
+ onShareAppMessage: () => {},
|
|
|
+ onShareTimeline: () => {},
|
|
|
+ getCurrentInstance: () => ({
|
|
|
+ proxy: {
|
|
|
+ $api: {
|
|
|
+ get: (url) => {
|
|
|
+ apiRequests.push(url)
|
|
|
+ return new Promise(() => {})
|
|
|
+ }
|
|
|
+ },
|
|
|
+ $showModal: () => {},
|
|
|
+ $showToast: () => {},
|
|
|
+ $refs: {}
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ useUserStore: () => userStore,
|
|
|
+ useGlobalShare: () => ({
|
|
|
+ isLogin: () => {
|
|
|
+ loginChecks++
|
|
|
+ return loggedIn
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ uni: {
|
|
|
+ getStorageSync: key => storage[key] || '',
|
|
|
+ showModal: options => modals.push(options),
|
|
|
+ showToast: () => {},
|
|
|
+ navigateTo: options => navigations.push(options),
|
|
|
+ reLaunch: options => navigations.push(options)
|
|
|
+ },
|
|
|
+ setTimeout: callback => callback(),
|
|
|
+ Date,
|
|
|
+ JSON,
|
|
|
+ console
|
|
|
+ }
|
|
|
+
|
|
|
+ vm.runInNewContext(
|
|
|
+ scriptSetup('pagesHome/activityDetail.vue') +
|
|
|
+ '\nglobalThis.__detail = { handleReviewMembers, handleApply, handleCancel, handleSignup, handleFill, showShareOptions, share }',
|
|
|
+ context
|
|
|
+ )
|
|
|
+ return { detail: context.__detail, lifecycle, navigations, apiRequests, modals, getLoginChecks: () => loginChecks }
|
|
|
+}
|
|
|
+
|
|
|
+async function loadAuthSession () {
|
|
|
+ const source = fs.readFileSync(path.resolve('common/utils/auth-session.js'), 'utf8')
|
|
|
+ return import(`data:text/javascript;base64,${Buffer.from(source).toString('base64')}`)
|
|
|
+}
|
|
|
+
|
|
|
+test('未登录用户点击首页活动直接进入详情', () => {
|
|
|
+ const { card, navigations } = mountActivityCard()
|
|
|
+
|
|
|
+ card.handleDetail({ id: 'activity-1' })
|
|
|
+
|
|
|
+ assert.equal(navigations.length, 1)
|
|
|
+ assert.equal(navigations[0].url, '/pagesHome/activityDetail?id=activity-1')
|
|
|
+})
|
|
|
+
|
|
|
+test('未登录进入详情时直接加载活动且不自动弹登录框', () => {
|
|
|
+ const { lifecycle, apiRequests, modals } = mountActivityDetail()
|
|
|
+
|
|
|
+ lifecycle.load({ id: 'activity-1' })
|
|
|
+
|
|
|
+ assert.deepEqual(apiRequests, ['/core/activity/activity-1'])
|
|
|
+ assert.equal(modals.length, 0)
|
|
|
+})
|
|
|
+
|
|
|
+test('未登录点击身份相关操作时中止操作并触发登录判断', () => {
|
|
|
+ const { detail, navigations, getLoginChecks } = mountActivityDetail({ loggedIn: false })
|
|
|
+
|
|
|
+ detail.handleReviewMembers()
|
|
|
+ detail.handleApply()
|
|
|
+ detail.handleCancel()
|
|
|
+ detail.handleSignup()
|
|
|
+ detail.handleFill()
|
|
|
+ detail.showShareOptions()
|
|
|
+
|
|
|
+ assert.equal(navigations.length, 0)
|
|
|
+ assert.equal(detail.share.value, false)
|
|
|
+ assert.equal(getLoginChecks(), 6)
|
|
|
+})
|
|
|
+
|
|
|
+test('已登录点击身份相关操作时继续执行原操作', async () => {
|
|
|
+ const { detail, navigations, getLoginChecks } = mountActivityDetail({ loggedIn: true })
|
|
|
+
|
|
|
+ detail.handleReviewMembers()
|
|
|
+ await detail.handleApply()
|
|
|
+ detail.handleCancel()
|
|
|
+ detail.handleSignup()
|
|
|
+ detail.handleFill()
|
|
|
+ detail.showShareOptions()
|
|
|
+
|
|
|
+ assert.equal(navigations.length, 5)
|
|
|
+ assert.equal(detail.share.value, true)
|
|
|
+ assert.equal(getLoginChecks(), 6)
|
|
|
+})
|
|
|
+
|
|
|
+test('登录完成后重新获取当前活动详情', () => {
|
|
|
+ const { lifecycle, apiRequests } = mountActivityDetail()
|
|
|
+ lifecycle.load({ id: 'activity-1' })
|
|
|
+
|
|
|
+ lifecycle.watchToken('', 'old-token')
|
|
|
+ lifecycle.watchToken('new-token', '')
|
|
|
+
|
|
|
+ assert.deepEqual(apiRequests, [
|
|
|
+ '/core/activity/activity-1',
|
|
|
+ '/core/activity/activity-1'
|
|
|
+ ])
|
|
|
+})
|
|
|
+
|
|
|
+test('登录态同时校验 token 和过期时间', async () => {
|
|
|
+ const { hasValidSession } = await loadAuthSession()
|
|
|
+ const now = 1000
|
|
|
+ const storage = values => ({ getStorageSync: key => values[key] || '' })
|
|
|
+
|
|
|
+ assert.equal(hasValidSession(storage({ token: 'token', expaireTime: 1001 }), now), true)
|
|
|
+ assert.equal(hasValidSession(storage({ token: 'token', expaireTime: 999 }), now), false)
|
|
|
+ assert.equal(hasValidSession(storage({ expaireTime: 1001 }), now), false)
|
|
|
+})
|