Files
youle_cocos/cocoscreator_projects/framework-tests/platform-login/login-accounts.test.ts
T

132 lines
12 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { LoginAccounts, nicknameHash } from '../../YouleNexus/assets/framework/adapters/native/login-accounts.ts';
import { resolveLoginPolicy } from '../../YouleNexus/assets/framework/presentation/login-policy.ts';
import { buildLoginRequest } from '../../YouleNexus/assets/framework/protocol/contracts/login-contract.ts';
test('logout expires visitor auto-login and clears cached player selection',()=>{
const values=new Map<string,string>();
const service=new LoginAccounts({storage:{removeItem:(k:string)=>{values.delete(k);},getItem:k=>values.get(k)??null,setItem:(k,v)=>{values.set(k,v);}},
random:()=>0.2,now:()=>100,gameid:'g',agentid:'a',policy:resolveLoginPolicy({raw:{},getValue:k=>k==='showVisitor'?1:null}),submit:()=>{},tip:()=>{}});
service.setAgreement(true);service.visitor();assert.ok(service.cached());
service.logout();assert.equal(service.cached(),null);
assert.equal(values.get('tsgame_playerid_ga'),'');
});
test('logout removes authorization caches and stays logged out after recreating accounts',()=>{
for(const mode of ['wechat','phone','visitor']){
const account=JSON.stringify({openid:'old',headimgurl:'a',nickname:'old',sex:1,city:'c',Province:'p',unionid:'old',telphone:'123'});
const values=new Map([['tsgame_wxinfo',account],['tsgame_devicePlayer',account],['tsgame_visitorinfo',account],
['tsgame_validtime','100000'],['tsgame_playerid_ga','42'],['tsgame_dLogin','1'],['tsgame_machineId_','installation']]);
const options={storage:{getItem:(k:string)=>values.get(k)??null,setItem:(k:string,v:string)=>{values.set(k,v);},removeItem:(k:string)=>{values.delete(k);}},
random:()=>0.2,now:()=>100,gameid:'g',agentid:'a',policy:{...resolveLoginPolicy({raw:{},getValue:()=>null}),showVisitor:mode==='visitor',deviceLogin:mode==='phone'},submit:()=>{},tip:()=>{}};
const service=new LoginAccounts(options);assert.ok(service.cached());service.logout();service.logout();
assert.equal(values.has('tsgame_wxinfo'),false);assert.equal(values.has('tsgame_devicePlayer'),false);
assert.equal(values.get('tsgame_validtime'),'0');assert.equal(values.get('tsgame_dLogin'),'0');assert.equal(values.get('tsgame_playerid_ga'),'');
assert.equal(new LoginAccounts(options).cached(),null);
assert.equal(values.get('tsgame_visitorinfo'),account);assert.equal(values.get('tsgame_machineId_'),'installation');
}
});
test('native authorization preserves provider numbers, agreement guard, callback and cache', () => {
const values=new Map<string,string>();const calls:number[]=[];const submitted:any[]=[];const tips:string[]=[];
const service=new LoginAccounts({storage:{removeItem:(k:string)=>{values.delete(k);},getItem:k=>values.get(k)??null,setItem:(k,v)=>{values.set(k,v);}},
settings:{accreditlogin:p=>calls.push(p),getcompareCode:()=>0},random:()=>0.2,now:()=>100,
gameid:'g',agentid:'a',policy:resolveLoginPolicy({raw:{},getValue:()=>null}),submit:(a,d)=>submitted.push([a,d]),tip:t=>tips.push(t)});
service.setAgreement(false);service.authorize('wechat');assert.deepEqual(calls,[]);assert.deepEqual(tips,['未同意协议']);
service.setAgreement(true);service.authorize('wechat');service.authorize('qq');assert.deepEqual(calls,[2,1]);
service.acceptNative({openid:'o',headimgurl:'a',nickname:'n',sex:1,city:'c',Province:'p',unionid:'u'},'bridge');
assert.equal(submitted[0][0].avatar,'a');assert.equal(submitted[0][0].province,'p');
assert.ok(values.has('tsgame_wxinfo'));assert.equal(service.cached()?.nickname,'n');
});
test('all login paths require the current agreement and rejected paths have no side effects',()=>{
const values=new Map<string,string>(),tips:string[]=[],submitted:unknown[]=[],native:number[]=[];
const service=new LoginAccounts({storage:{removeItem:(k:string)=>{values.delete(k);},getItem:k=>values.get(k)??null,setItem:(k,v)=>{values.set(k,v);}},
settings:{getcompareCode:()=>0,accreditlogin:p=>native.push(p)},random:()=>0.2,now:()=>100,
gameid:'g',agentid:'a',policy:resolveLoginPolicy({raw:{},getValue:()=>null}),submit:a=>submitted.push(a),tip:t=>tips.push(t)});
assert.equal(service.agreed,true);service.setAgreement(false);
service.authorize('wechat');service.authorize('qq');service.visitor();service.device();service.phone('00123','000456');service.autoLogin();
service.acceptNative({},'global');service.acceptNative({},'bridge');
for(let i=0;i<5;i++)service.hiddenFirst();service.hiddenSecond();
assert.equal(tips.length,9);assert.ok(tips.every(t=>t==='未同意协议'));
assert.equal(values.size,0);assert.equal(submitted.length,0);assert.equal(native.length,0);
service.setAgreement(true);service.visitor();assert.equal(submitted.length,1);
});
test('successful device login persists server identity for the next automatic login', () => {
const values=new Map<string,string>();const submitted:any[]=[];
const service=new LoginAccounts({storage:{removeItem:(k:string)=>{values.delete(k);},getItem:k=>values.get(k)??null,setItem:(k,v)=>{values.set(k,v);}},
random:()=>0.2,now:()=>100,gameid:'g',agentid:'a',policy:{...resolveLoginPolicy({raw:{},getValue:()=>null}),deviceLogin:true},
submit:(a,d)=>submitted.push([a,d]),tip:()=>{}});
service.loginSucceeded({state:0,playerid:42,openid:'server-o',avatar:'server-a',nickname:'server-n',sex:2,city:'c',province:'p',unionid:'u',tel:'13800138000'}, {enabled:true,telphone:'13800138000'});
service.autoLogin();assert.equal(submitted[0][0].openid,'server-o');
assert.deepEqual(submitted[0][1],{enabled:true,telphone:'13800138000'});
assert.equal(values.get('tsgame_playerid_ga'),'42');assert.equal(values.get('tsgame_dLogin'),'1');
});
test('visitor login and cached visitor stay phone-free when both login buttons are enabled', () => {
const values=new Map<string,string>();const submitted:any[]=[];
const options={storage:{removeItem:(k:string)=>{values.delete(k);},getItem:(k:string)=>values.get(k)??null,setItem:(k:string,v:string)=>{values.set(k,v);}},
random:()=>0.2,now:()=>100,gameid:'g',agentid:'a',policy:{...resolveLoginPolicy({raw:{},getValue:()=>null}),showVisitor:true,deviceLogin:true},
submit:(a:unknown,d:unknown)=>submitted.push([a,d]),tip:()=>{}};
const service=new LoginAccounts(options);
service.visitor();assert.deepEqual(submitted[0][1],{enabled:false});
const response={state:0,playerid:42,openid:'server',avatar:'a',nickname:'n',sex:0,city:'c',province:'p',unionid:'server'};
assert.doesNotThrow(()=>service.loginSucceeded(response,submitted[0][1]));
assert.equal(values.get('tsgame_playerid_ga'),'42');
assert.equal(JSON.parse(values.get('tsgame_devicePlayer')!).sex,0);assert.equal(values.get('tsgame_dLogin'),'1');
const reloaded=new LoginAccounts(options);reloaded.autoLogin();
assert.deepEqual(submitted[1],[submitted[0][0],{enabled:false}]);
assert.doesNotThrow(()=>reloaded.loginSucceeded(response,submitted[1][1]));
});
test('phone cache writes match legacy before submit, denial, and successful server response',()=>{
for(const showVisitor of [false,true])for(const deviceLogin of [false,true]){
const values=new Map<string,string>();let now=100;let submitted:any;
const service=new LoginAccounts({storage:{getItem:k=>values.get(k)??null,setItem:(k,v)=>{values.set(k,v);},removeItem:k=>{values.delete(k);}},
random:()=>0.2,now:()=>now,gameid:'g',agentid:'a',policy:{...resolveLoginPolicy({raw:{},getValue:()=>null}),showVisitor,deviceLogin},
submit:(account,mode)=>{submitted={account,mode};assert.equal(values.has('tsgame_visitorinfo'),showVisitor);assert.equal(values.has('tsgame_devicePlayer'),false);},tip:()=>{}});
service.phone('00123','000456');
const before=[...values];assert.throws(()=>service.loginSucceeded({state:-1,msg:'短信验证码不正确'},submitted.mode));assert.deepEqual([...values],before);
now=200;
service.loginSucceeded({state:0,playerid:42,openid:'server',avatar:'avatar',nickname:'server name',sex:0,city:'city',province:'province',unionid:'server union',tel:'00123'},submitted.mode);
assert.equal(values.has('tsgame_devicePlayer'),deviceLogin);
if(deviceLogin){assert.deepEqual(JSON.parse(values.get('tsgame_devicePlayer')!),{openid:'server',headimgurl:'avatar',nickname:'server name',sex:0,city:'city',Province:'province',unionid:'server union',telphone:'00123'});assert.equal(values.get('tsgame_validtime'),String(200+48*60*60*1000));assert.equal(values.get('tsgame_dLogin'),'1');}
if(showVisitor)assert.equal(JSON.parse(values.get('tsgame_visitorinfo')!).openid,'phone_00123');
assert.equal(values.get('tsgame_playerid_ga'),'42');
assert.equal([...values.values()].some(v=>v.includes('000456')),false,'SMS code is not persisted');
}
});
test('global and WVJB authorization retain their distinct legacy cache destinations', () => {
const values=new Map<string,string>();
const service=new LoginAccounts({storage:{removeItem:(k:string)=>{values.delete(k);},getItem:k=>values.get(k)??null,setItem:(k,v)=>{values.set(k,v);}},
random:()=>0.2,now:()=>100,gameid:'g',agentid:'a',policy:{...resolveLoginPolicy({raw:{},getValue:()=>null}),showVisitor:true},submit:()=>{},tip:()=>{}});
const data={openid:'o',headimgurl:'a',nickname:'n',sex:1,city:'c',Province:'p',unionid:'u'};
service.acceptNative(data,'global');assert.ok(values.has('tsgame_visitorinfo'));assert.equal(values.has('tsgame_wxinfo'),false);
service.acceptNative(data,'bridge');assert.ok(values.has('tsgame_wxinfo'));
});
test('legacy nickname MD5 matches standard vectors',()=>{
assert.equal(nicknameHash(''),'d41d8cd98f00b204e9800998ecf8427e');
assert.equal(nicknameHash('abc'),'900150983cd24fb0d6963f7d28e17f72');
});
test('phone login preserves leading zeros and legacy visitor cache before submitting', () => {
const values=new Map<string,string>();const tips:string[]=[];const submissions:unknown[]=[];
const service=new LoginAccounts({storage:{removeItem:(k:string)=>{values.delete(k);},getItem:k=>values.get(k)??null,setItem:(k,v)=>{values.set(k,v);}},
random:()=>0.2,now:()=>100,gameid:'g',agentid:'a',policy:{...resolveLoginPolicy({raw:{},getValue:()=>null}),showVisitor:true},
submit:(account,mode)=>{assert.equal(JSON.parse(values.get('tsgame_visitorinfo')!).telphone,'00123');submissions.push([account,mode]);},tip:m=>tips.push(m)});
service.phone('','000456');service.phone('00123','');
assert.equal(submissions.length,0);assert.equal(values.size,0);
assert.deepEqual(tips,['手机号与验证码均不能为空!','手机号与验证码均不能为空!']);
service.phone('00123','000456');
assert.deepEqual((submissions[0] as unknown[])[1],{enabled:true,telphone:'00123',smmcode:'000456'});
assert.equal(values.has('tsgame_devicePlayer'),false);
});
test('phone login emits original sms fields and does not masquerade as cached auto login', () => {
const values=new Map<string,string>();const submitted:any[]=[];
const service=new LoginAccounts({storage:{removeItem:(k:string)=>{values.delete(k);},getItem:k=>values.get(k)??null,setItem:(k,v)=>{values.set(k,v);}},
random:()=>0.2,now:()=>100,gameid:'g',agentid:'a',policy:resolveLoginPolicy({raw:{},getValue:()=>null}),
submit:(a,d)=>submitted.push([a,d]),tip:()=>{}});
service.phone('13800138000','123456');
const [account,mode]=submitted[0];assert.equal(account.unionid,'phone_13800138000');
const result=buildLoginRequest({identity:{agentid:'a',gameid:'g',channelid:'c',marketid:4,version:1}},account,
{location:null,machineid:'m',machineroom:'',deviceLogin:mode,loginPlayerId:{enabled:false}});
assert.equal(result.data.telphone,'13800138000');assert.equal(result.data.smmcode,'123456');assert.equal(result.data.telphoneAuto,false);
});