const { test } = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const vm = require('node:vm') const ts = require(process.env.TEST_TYPESCRIPT || 'typescript') const root = path.join(__dirname, '..') function load(file, mocks = {}, globals = {}) { const source = fs.readFileSync(path.join(root, file), 'utf8') const output = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX } }).outputText const module = { exports: {} } const jsx = (type, props) => ({ type: typeof type === 'string' ? type : 'component', ...props }) const requireMock = id => { if (id in mocks) return mocks[id] if (id === 'react/jsx-runtime') return { jsx, jsxs: jsx, Fragment: 'fragment' } if (id === '@/lib/viewer') return load('src/lib/viewer.ts', mocks) if (id === '@/lib/launch') return load('src/lib/launch.ts') if (id.startsWith('node:') || ['crypto', 'util'].includes(id)) return require(id) if (id.endsWith('.css')) return {} return { __esModule: true, default: () => null } } vm.runInNewContext(output, { module, exports: module.exports, require: requireMock, process, console, ...globals }, { filename: file }) return module.exports } const response = { NextResponse: { json: (body, options = {}) => ({ body, status: options.status || 200 }) } } const noIO = { getPayload: () => { throw new Error('Unexpected database access') } } test('free launch cannot be switched to billing by Stripe environment or date', async () => { const old = { ...process.env } try { for (const mode of [undefined, 'free', 'paid']) { if (mode) process.env.LAUNCH_MODE = mode; else delete process.env.LAUNCH_MODE process.env.STRIPE_SECRET_KEY = 'test-present'; process.env.STRIPE_WEBHOOK_SECRET = 'test-present'; process.env.STRIPE_PRICE_ID = 'test-present' const policy = load('src/lib/launch.ts') assert.equal(policy.billingEnabled(), false, `billing must stay disabled for env mode ${mode}`) assert.equal(policy.freeEarlyAccess(), true) const result = await load('src/app/api/subscribe/route.ts', { 'next/server': response, payload: noIO }).POST() assert.equal(result.status, 503); assert.ok(result.body.error); assert.equal(result.body.url, undefined) } } finally { process.env = old } }) test('unverified notification signup rejects without storing email or sending mail', async () => { const result = await load('src/app/api/notify/route.ts', { 'next/server': response, payload: noIO }).POST(new Request('https://example.test/api/notify', { method: 'POST', body: JSON.stringify({ email: 'reader@example.test' }) })) assert.equal(result.status, 503); assert.ok(result.body.error); assert.equal(result.body.ok, undefined) }) test('policies and public entry points describe current free reading without signup or notification form', async () => { for (const name of ['terms', 'privacy']) { const page = load(`src/app/(frontend)/${name}/page.tsx`).default() const text = JSON.stringify(page) assert.doesNotMatch(text, /مسودة|يجب إضافة|قبل الإطلاق يجب|تجريبية للواجهة/) assert.match(text, /2026-10-10/); assert.match(text, /Anwarpy/); assert.match(text, /hello@anwarpy.ai/) } const privacy = JSON.stringify(load('src/app/(frontend)/privacy/page.tsx').default()) assert.match(privacy, /Cloudflare/); assert.match(privacy, /سنة واحدة/); assert.match(privacy, /تلقائي/) const subscription = await load('src/app/(frontend)/subscription/page.tsx', { payload: { getPayload: async () => ({ auth: async () => ({ user: null }), find: async () => ({ docs: [] }) }) }, 'next/headers': { headers: async () => ({}) }, }).default() const rendered = JSON.stringify(subscription) assert.doesNotMatch(rendered, /المقدمة فقط|حساب مجاني|شهرياً|تُضاف أدلة جديدة كل شهر/) assert.match(rendered, /دون حساب/); assert.match(rendered, /مستقبلاً/) const source = fs.readFileSync(path.join(root, 'src/app/(frontend)/subscription/page.tsx'), 'utf8') assert.doesNotMatch(source, /NotifyForm|SubscribeButton/) const footer = JSON.stringify(load('src/components/footer.tsx').default()) assert.doesNotMatch(footer, /\/signup/) }) test('frontend layout displays the exact trial banner on every frontend route', () => { const layout = 'src/app/(frontend)/layout.tsx' assert.ok(fs.existsSync(path.join(root, layout)), 'shared frontend layout is required') const tree = JSON.stringify(load(layout).default({ children: 'page content' })) assert.match(tree, /اطلاق تجريبي/); assert.match(tree, /دون حساب/); assert.match(tree, /تلقائياً/) assert.match(tree, /aria-label/) }) test('missing download payload never reports success and valid payload creates a file', () => { for (const key of ['missing.md', 'agent-state.md']) { const button = { dataset: { dl: key }, textContent: 'تنزيل', addEventListener: (event, fn) => { button.click = fn } } const blobs = []; let clicked = 0 const document = { getElementById: () => null, querySelectorAll: () => [button], body: { append: () => {} }, createElement: () => ({ click: () => clicked++, remove: () => {} }) } const react = { useEffect: fn => fn(), useState: value => [value, () => {}] } load('src/app/(frontend)/posts/[slug]/post-extras.tsx', { react }, { document, Blob: class { constructor(body) { blobs.push(body) } }, URL: { createObjectURL: () => 'blob:test', revokeObjectURL: () => {} }, setTimeout: () => {}, }).default({ slug: 'fixture', loggedIn: false }) button.click({ currentTarget: button }) if (key === 'missing.md') { assert.notEqual(button.textContent, 'تم التنزيل ✓'); assert.equal(clicked, 0); assert.equal(blobs.length, 0) } else { assert.equal(clicked, 1); assert.ok(blobs[0][0].length > 20); assert.equal(button.textContent, 'تم التنزيل ✓') } } }) test('home and library entry points label intended membership as future, never require signup for reading', () => { for (const file of ['src/app/(frontend)/page.tsx', 'src/app/(frontend)/articles/page.tsx', 'src/app/(frontend)/topics/[topic]/page.tsx']) { const source = fs.readFileSync(path.join(root, file), 'utf8') assert.match(source, /accessLabel/) assert.doesNotMatch(source, /العضوية تفتح الأدلة|للأعضاء، وتُضاف/) } assert.match(fs.readFileSync(path.join(root, 'src/components/site-links.ts'), 'utf8'), /الوصول المبكر/) assert.doesNotMatch(fs.readFileSync(path.join(root, 'src/app/(frontend)/login/page.tsx'), 'utf8'), /\/signup/) }) test('private VIP files remain protected during free launch', async () => { let diskRead = false const result = await load('src/app/api/files/[id]/route.ts', { 'next/server': response, payload: { getPayload: async () => ({ findByID: async () => ({ id: 1, access: 'vip', filename: 'private.md', mimeType: 'text/plain' }) }) }, '@/lib/viewer': { getViewer: async () => null }, '@/collections/Files': { FILES_DIR: '/not-used' }, 'node:fs/promises': { readFile: async () => { diskRead = true; return Buffer.from('private') } }, }).GET({}, { params: Promise.resolve({ id: '1' }) }) assert.equal(result.status, 401); assert.equal(diskRead, false) }) test('source traceability is never readable and users remain admin-created only', () => { const posts = load('src/collections/Posts.ts').default const sourceId = posts.fields.find(field => field.name === 'sourceId') assert.equal(typeof sourceId.access?.read, 'function') assert.equal(sourceId.access.read({ req: { user: null } }), false) assert.equal(sourceId.access.read({ req: { user: { role: 'admin' } } }), false) assert.equal(posts.access.read({ req: { user: null } }).status.equals, 'published') const users = load('src/collections/Users.ts').default assert.equal(users.access.create({ req: { user: null } }), false) assert.equal(users.access.create({ req: { user: { role: 'free' } } }), false) assert.equal(users.access.create({ req: { user: { role: 'admin' } } }), true) }) test('unused notification and checkout controls also fail closed if reused', () => { const react = { useState: value => [value, () => {}] } const notify = JSON.stringify(load('src/app/(frontend)/subscription/notify-form.tsx', { react }).default()) assert.doesNotMatch(notify, /\"type\":\"input\"|\"type\":\"form\"/) const checkout = JSON.stringify(load('src/app/(frontend)/subscription/subscribe-button.tsx', { react }).default({ loggedIn: false })) assert.doesNotMatch(checkout, /\/signup|اشترك/); assert.match(checkout, /\/articles/) assert.doesNotMatch(fs.readFileSync(path.join(root, 'src/app/(frontend)/account-settings/page.tsx'), 'utf8'), /\/signup/) }) test('all source TypeScript and TSX files transpile without syntax diagnostics', () => { let count = 0 function walk(dir) { for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { const full = path.join(dir, entry.name) if (entry.isDirectory()) walk(full) else if (/\.tsx?$/.test(entry.name) && !entry.name.endsWith('.d.ts')) { const result = ts.transpileModule(fs.readFileSync(full, 'utf8'), { fileName: full, reportDiagnostics: true, compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX } }) const errors = (result.diagnostics || []).filter(d => d.category === ts.DiagnosticCategory.Error) assert.equal(errors.length, 0, `${full}: ${errors.map(d => ts.flattenDiagnosticMessageText(d.messageText, '\n')).join('; ')}`) count++ } } } walk(path.join(root, 'src')); assert.ok(count > 50); console.log(`Syntax transpile checked ${count} source files (not full type/build validation)`) }) module.exports = { load, response, noIO }