const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const vm = require('node:vm'); const ts = require('typescript'); function load(path, cc, dependencies) { const context = { cc, exports: {}, require: id => dependencies(id), setTimeout, clearTimeout }; vm.runInNewContext(ts.transpileModule(fs.readFileSync(path, 'utf8'), { compilerOptions: { experimentalDecorators: true, module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017, } }).outputText, context); return context.exports.default; } test('test entry requires develop/trial and a distinct configured test origin', () => { let version = '开发版'; const utils = { httpip: 'https://production.example/', testHttpip: 'https://test.example/' }; const cc = { fx: { GameTool: { getWechatGameVersion: () => version } } }; const api = load('assets/Script/seven_day_gift/SevenDayGiftBootstrapApi.ts', cc, () => ({ default: utils })); for (const v of ['正式版', '未知版本', '网页版']) { version = v; assert.equal(api.getTestEnvironment().allowed, false); } for (const v of ['开发版', '体验版']) { version = v; assert.equal(api.getTestEnvironment().allowed, true); } utils.testHttpip = 'https://PRODUCTION.example/test/'; assert.equal(api.getTestEnvironment().allowed, false); utils.testHttpip = ''; assert.equal(api.getTestEnvironment().allowed, false); }); test('cache clearing preserves other users, activities and rounds and blocks stale snapshots', () => { const store = new Map(); let uid = 'user1', url = 'https://test.example/'; const api = { getUid: () => uid, getTestEnvironment: () => ({ allowed: true, baseUrl: url }) }; const cc = { Component: class {}, _decorator: { ccclass: x => x }, fx: { StorageMessage: { getStorage: key => store.get(key), setStorage: (key, value) => store.set(key, value), removeStorage: key => store.delete(key), } } }; const Panel = load('assets/seven_day_gift/test/SevenDayTest.ts', cc, () => ({ default: api })); const p = new Panel(); p.render = () => {}; p.snapshot = { activityId: 'activity1', startAt: 123 }; p.snapshotUid = uid; p.snapshotUrl = url; const key = (user, activity, start, day) => user + ':' + JSON.stringify([activity, start, day]); const own = key(uid, 'activity1', 123, 1), own2 = key(uid, 'activity1', 123, 2); const other = [key('user2', 'activity1', 123, 1), key(uid, 'activity2', 123, 1), key(uid, 'activity1', 456, 1)]; const records = Object.fromEntries([own, own2, ...other].map(k => [k, true])); store.set('seven_day_gift_processed_claims_v1', records); p.isActivityOpen = () => true; p.clearCache(true); assert.equal(records[own], true); p.isActivityOpen = () => false; uid = 'user2'; p.clearCache(true); assert.equal(records[own], true); uid = 'user1'; url = 'https://changed.example/'; p.clearCache(true); assert.equal(records[own], true); url = p.snapshotUrl; p.clearCache(true); assert.equal(records[own], undefined); assert.equal(records[own2], undefined); other.forEach(k => assert.equal(records[k], true)); const auto = 'seven_day_gift_auto_open_v1:user1:activity1'; store.set(auto, '123'); store.set('seven_day_gift_auto_open_v1:user2:activity1', '123'); p.clearCache(false); assert.equal(store.has(auto), false); assert.equal(store.get('seven_day_gift_auto_open_v1:user2:activity1'), '123'); }); test('debug prefab references and required controls exist', () => { const a = JSON.parse(fs.readFileSync('assets/seven_day_gift/test/SevenDayTest.prefab')); function walk(x) { if (!x || typeof x !== 'object') return; if ('__id__' in x) assert.ok(a[x.__id__]); Object.values(x).forEach(walk); } a.forEach(walk); for (const name of ['entry', 'panel', 'close', 'query', 'clearClaim', 'clearAuto', 'recheck', 'viewport', 'content']) assert.equal(a.filter(n => n.__type__ === 'cc.Node' && n._name === name).length, 1); assert.equal(a.find(n => n._name === 'panel')._active, false); for (const node of a.filter(n => n.__type__ === 'cc.Node')) { for (const ref of node._components) { assert.ok(ref && a[ref.__id__], 'no null component slots'); assert.ok(a[ref.__id__].__type__.startsWith('cc.'), 'UI prefab must not serialize custom script references'); } } }); test('test entry attaches the registered constructor without calling getComponent on the prefab', () => { let added = 0, initialized = false, mounted = false; class TestPanel {} const panel = { initialize() { assert.equal(node.active, false); initialized = true; } }; const node = { active: true, getComponent: () => { throw new TypeError("Cannot read property 'constructor' of null"); }, addComponent(type) { assert.equal(type, TestPanel); added++; return panel; }, destroy() { assert.fail('unexpected destruction'); } }; const bundle = { load(path, type, done) { assert.equal(path, 'test/SevenDayTest'); done(null, {}); } }; const canvas = { getComponent: () => ({ loadHomeBundleWithDependencies(name, priority, done) { done(null, bundle); } }), addChild(child) { assert.equal(child, node); assert.equal(initialized, true); mounted = true; } }; const api = { getTestEnvironment: () => ({ allowed: true }) }; const cc = { Component: class {}, Prefab: class {}, _decorator: { ccclass: x => x }, js: { getClassByName: name => { assert.equal(name, 'SevenDayTest'); return TestPanel; } }, find: () => canvas, isValid: () => true, instantiate: () => node }; const Host = load('assets/Script/seven_day_gift/SevenDayGiftHost.ts', cc, () => ({ default: api })); const host = new Host(); host.node = {}; host.loadTestEntry(); assert.equal(added, 1); assert.equal(mounted, true); assert.equal(node.active, true); }); test('entry touch opens panel and close touch hides it', () => { const api = { getTestEnvironment: () => ({ allowed: true }) }; const controls = new Map(); function control(name) { if (!controls.has(name)) controls.set(name, { active: false, handlers: {}, on(event, action) { this.handlers[event] = action; }, getChildByName: control, getComponent: () => ({}), addComponent: () => ({ roundRect() {}, fill() {} }), }); return controls.get(name); } const cc = { Component: class {}, Graphics: class {}, Label: class {}, color: () => ({}), Node: { EventType: { TOUCH_END: 'touchend' } }, _decorator: { ccclass: x => x } }; const Panel = load('assets/seven_day_gift/test/SevenDayTest.ts', cc, () => ({ default: api })); const p = new Panel(); p.node = control('root'); p.render = () => {}; p.onLoad(); control('entry').handlers.touchend({ stopPropagation() {} }); assert.equal(control('panel').active, true); control('close').handlers.touchend({ stopPropagation() {} }); assert.equal(control('panel').active, false); });