mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
64 lines
3.3 KiB
TypeScript
64 lines
3.3 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
||
import { readdirSync, readFileSync, statSync } from 'node:fs'
|
||
import { join } from 'node:path'
|
||
import { SNAPSHOT, asRules, disclosed, earning, kindsOf, tier } from '../../lib/hanzo/rewards'
|
||
import rules from '../../lib/data/rewards-rules.json' with { type: 'json' }
|
||
|
||
/**
|
||
* THE REWARDS RULES ARE THE CLOUD'S SHAPE, AND THE PAGES SAY WHAT POINTS ARE.
|
||
*
|
||
* The snapshot is the cloud's Rules (apps/rewards rules.go) as it serves them,
|
||
* read by the one parser the pages use; an answer of an earlier shape reads as
|
||
* no table. The words the rewards surfaces print never call points money: no
|
||
* payout, no airdrop, nothing earned as cash, and the founder program offers no
|
||
* free compute.
|
||
*/
|
||
|
||
test('the snapshot reads as the cloud’s rules: its tabs, the ladder from Hacker, credit under caps and no payouts', () => {
|
||
expect(SNAPSHOT.tabs.map((t) => t.id)).toEqual(['overall', 'builders', 'contributors', 'advocates'])
|
||
expect(SNAPSHOT.levels[0]).toEqual({ name: 'Hacker', points: 0, substantive: false })
|
||
expect(SNAPSHOT.payouts).toBe(false)
|
||
expect(SNAPSHOT.chain.minting).toBe(SNAPSHOT.chain.contract !== '')
|
||
expect(SNAPSHOT.redeem.pointsPerDollar).toBe(rules.redeem.pointsPerDollar)
|
||
expect(SNAPSHOT.kinds).toHaveLength(rules.kinds.length)
|
||
expect(SNAPSHOT.badges.find((b) => b.id === 'zen-pioneer')?.kinds).toEqual([])
|
||
})
|
||
|
||
test('an answer of an earlier shape is no table', () => {
|
||
const { tabs: _gone, ...older } = rules
|
||
expect(asRules(older)).toBeNull()
|
||
expect(asRules({})).toBeNull()
|
||
})
|
||
|
||
test('the ways to earn leave out the ledger’s bookkeeping', () => {
|
||
const ids = earning(SNAPSHOT).flatMap((s) => kindsOf(SNAPSHOT, s.id).map((k) => k.id))
|
||
for (const book of ['legacy', 'reversal', 'redeem', 'unredeem']) expect(ids).not.toContain(book)
|
||
expect(earning(SNAPSHOT).map((s) => s.id)).not.toContain('redeemed')
|
||
expect(ids).toContain('tier')
|
||
})
|
||
|
||
test('a bounty’s tier is the kind its label names, and a post’s disclosure is the rules’ quoted line', () => {
|
||
expect(tier(SNAPSHOT, ['bounty', 'bounty:standard'])?.id).toBe('bounty-standard')
|
||
expect(tier(SNAPSHOT, ['Bounty:Advanced'])?.points).toBe(rules.kinds.find((k) => k.id === 'bounty-advanced')?.points)
|
||
expect(tier(SNAPSHOT, ['bounty', 'bug'])).toBeUndefined()
|
||
expect(disclosed(SNAPSHOT)).toBe('I earn Hanzo Rewards points.')
|
||
})
|
||
|
||
const ROOT = join(import.meta.dirname, '..', '..')
|
||
const SURFACES = ['components/rewards', 'components/beta', 'app/(marketing)/leaderboard', 'app/(marketing)/bounty', 'app/(marketing)/referral', 'app/(marketing)/founder', 'components/settings/General.tsx', 'public/llms.txt']
|
||
const files = (path: string): string[] => (statSync(path).isDirectory() ? readdirSync(path).flatMap((n) => files(join(path, n))) : [path])
|
||
const commentary = (line: string) => /^\s*(\*|\/\/|\/\*)/.test(line)
|
||
|
||
test('the rewards surfaces never call points money, and the founder program offers no free compute', () => {
|
||
const said: string[] = []
|
||
for (const file of SURFACES.flatMap((s) => files(join(ROOT, s)))) {
|
||
readFileSync(file, 'utf8')
|
||
.split('\n')
|
||
.forEach((line, i) => {
|
||
if (commentary(line)) return
|
||
if (/\b(payouts?|airdrops?|earn money|cash out)\b|compute credits?|pro compute|free pro ai/i.test(line)) said.push(`${file.slice(ROOT.length + 1)}:${i + 1}: ${line.trim()}`)
|
||
})
|
||
}
|
||
expect(said).toEqual([])
|
||
})
|