mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-20 07:38:34 +02:00
217 lines
8.9 KiB
JavaScript
217 lines
8.9 KiB
JavaScript
const {
|
|
buildCommerceDisclosure,
|
|
safeContactUrl,
|
|
validatePaidAcknowledgement
|
|
} = require('../src/config/commerceDisclosurePolicy');
|
|
const PaymentHandlers = require('../src/network/paymentHandlers');
|
|
|
|
function manager(overrides = {}) {
|
|
return {
|
|
cryptoType: 'XMR',
|
|
currencyLabel: 'sXMR',
|
|
network: 'stagenet',
|
|
isTestNetwork: true,
|
|
gameName: 'Monerogue',
|
|
paymentsEnabled: true,
|
|
freePlayEnabled: true,
|
|
directModeEnabled: true,
|
|
creditsModeEnabled: true,
|
|
payoutsEnabled: true,
|
|
isPayoutEnabledForMode: mode => mode === 'PAID_SINGLE',
|
|
...overrides
|
|
};
|
|
}
|
|
|
|
function env(overrides = {}) {
|
|
return {
|
|
NODE_ENV: 'production',
|
|
LEGAL_POLICY_VERSION: '2026-07-21-v1',
|
|
TERMS_EFFECTIVE_DATE: '2026-07-21',
|
|
MINIMUM_AGE: '21',
|
|
PAID_ACKNOWLEDGEMENT_REQUIRED: 'true',
|
|
OPERATOR_NAME: 'Test Operator',
|
|
OPERATOR_CONTACT_URL: 'mailto:support@example.invalid',
|
|
MATCH_ENABLED: 'false',
|
|
...overrides
|
|
};
|
|
}
|
|
|
|
describe('commerce disclosure and paid-action policy', () => {
|
|
test('describes active test-network payout mode without conflating it with mainnet', () => {
|
|
const disclosure = buildCommerceDisclosure(manager(), env());
|
|
|
|
expect(disclosure).toEqual(expect.objectContaining({
|
|
policyVersion: '2026-07-21-v1',
|
|
minimumAge: 21,
|
|
paidAcknowledgementRequired: true
|
|
}));
|
|
expect(disclosure.service).toEqual(expect.objectContaining({
|
|
network: 'stagenet',
|
|
isTestNetwork: true,
|
|
paidPrestigeOnly: false,
|
|
soloPayoutsEnabled: true
|
|
}));
|
|
});
|
|
|
|
test('describes paid prestige separately when every payout path is off', () => {
|
|
const disclosure = buildCommerceDisclosure(manager({
|
|
cryptoType: 'WOW', currencyLabel: 'WOW', network: 'mainnet', isTestNetwork: false,
|
|
payoutsEnabled: false, isPayoutEnabledForMode: () => false
|
|
}), env());
|
|
|
|
expect(disclosure.service.paidPrestigeOnly).toBe(true);
|
|
expect(disclosure.service.anyPayoutsEnabled).toBe(false);
|
|
});
|
|
|
|
test('does not advertise a stale solo payout flag when that paid mode is disabled', () => {
|
|
const disclosure = buildCommerceDisclosure(manager({
|
|
directModeEnabled: false,
|
|
creditsModeEnabled: true,
|
|
isPayoutEnabledForMode: mode => mode === 'PAID_SINGLE'
|
|
}), env());
|
|
|
|
expect(disclosure.service.directPaidEntryEnabled).toBe(false);
|
|
expect(disclosure.service.paidCreditsEnabled).toBe(true);
|
|
expect(disclosure.service.soloPayoutsEnabled).toBe(false);
|
|
|
|
const activeCreditsPayout = buildCommerceDisclosure(manager({
|
|
directModeEnabled: false,
|
|
creditsModeEnabled: true,
|
|
isPayoutEnabledForMode: mode => mode === 'PAID_CREDITS'
|
|
}), env());
|
|
expect(activeCreditsPayout.service.soloPayoutsEnabled).toBe(true);
|
|
|
|
const noPaidModes = buildCommerceDisclosure(manager({
|
|
directModeEnabled: false,
|
|
creditsModeEnabled: false,
|
|
isPayoutEnabledForMode: () => true
|
|
}), env());
|
|
expect(noPaidModes.service.soloPayoutsEnabled).toBe(false);
|
|
expect(noPaidModes.service.anyPayoutsEnabled).toBe(false);
|
|
});
|
|
|
|
test('fails closed on missing, stale, incomplete, or testnet-unaware acknowledgement', () => {
|
|
const disclosure = buildCommerceDisclosure(manager(), env());
|
|
const good = {
|
|
policyVersion: disclosure.policyVersion,
|
|
ageEligible: true,
|
|
termsRead: true,
|
|
riskAccepted: true,
|
|
testnetUnderstood: true
|
|
};
|
|
|
|
expect(validatePaidAcknowledgement(null, disclosure).ok).toBe(false);
|
|
expect(validatePaidAcknowledgement({ ...good, policyVersion: 'old' }, disclosure).code).toBe('PAID_ACK_VERSION');
|
|
expect(validatePaidAcknowledgement({ ...good, riskAccepted: false }, disclosure).code).toBe('PAID_ACK_INCOMPLETE');
|
|
expect(validatePaidAcknowledgement({ ...good, testnetUnderstood: false }, disclosure).code).toBe('PAID_ACK_TESTNET');
|
|
expect(validatePaidAcknowledgement({ ...good, extra: true }, disclosure).code).toBe('PAID_ACK_MALFORMED');
|
|
expect(validatePaidAcknowledgement({
|
|
policyVersion: disclosure.policyVersion,
|
|
ageEligible: true,
|
|
termsRead: true,
|
|
riskAccepted: true
|
|
}, disclosure).code).toBe('PAID_ACK_MALFORMED');
|
|
expect(validatePaidAcknowledgement(good, disclosure)).toEqual({
|
|
ok: true,
|
|
code: 'ACKNOWLEDGED',
|
|
acknowledgement: Object.freeze(good)
|
|
});
|
|
});
|
|
|
|
test('mainnet acknowledgement is canonical and carries an explicit false testnet flag', () => {
|
|
const disclosure = buildCommerceDisclosure(manager({
|
|
cryptoType: 'WOW',
|
|
currencyLabel: 'WOW',
|
|
network: 'mainnet',
|
|
isTestNetwork: false
|
|
}), env());
|
|
const good = {
|
|
policyVersion: disclosure.policyVersion,
|
|
ageEligible: true,
|
|
termsRead: true,
|
|
riskAccepted: true,
|
|
testnetUnderstood: false
|
|
};
|
|
|
|
expect(validatePaidAcknowledgement(good, disclosure)).toEqual({
|
|
ok: true,
|
|
code: 'ACKNOWLEDGED',
|
|
acknowledgement: Object.freeze(good)
|
|
});
|
|
expect(validatePaidAcknowledgement({ ...good, testnetUnderstood: true }, disclosure).code)
|
|
.toBe('PAID_ACK_MALFORMED');
|
|
});
|
|
|
|
test('keeps acknowledgement UI enabled for paid match entitlements while invoice intake is off', () => {
|
|
const disclosure = buildCommerceDisclosure(manager({
|
|
paymentsEnabled: false,
|
|
directModeEnabled: false,
|
|
creditsModeEnabled: false,
|
|
freePlayEnabled: true,
|
|
_getMatchEconomies: () => ({ free: true, credits_prestige: true })
|
|
}), env({ PAID_ACKNOWLEDGEMENT_REQUIRED: 'false', MATCH_ENABLED: 'true' }));
|
|
|
|
expect(disclosure.service.paymentsEnabled).toBe(false);
|
|
expect(disclosure.paidAcknowledgementRequired).toBe(true);
|
|
});
|
|
|
|
test('allows no acknowledgement only where the policy is actually disabled', () => {
|
|
const disclosure = buildCommerceDisclosure(manager({
|
|
paymentsEnabled: false,
|
|
directModeEnabled: false,
|
|
creditsModeEnabled: false,
|
|
freePlayEnabled: false
|
|
}), {
|
|
NODE_ENV: 'test', PAID_ACKNOWLEDGEMENT_REQUIRED: 'false'
|
|
});
|
|
expect(validatePaidAcknowledgement(null, disclosure)).toEqual({
|
|
ok: true, code: 'NOT_REQUIRED', acknowledgement: null
|
|
});
|
|
});
|
|
|
|
test('contact URLs reject executable and unrelated schemes', () => {
|
|
expect(safeContactUrl('javascript:alert(1)')).toBeNull();
|
|
expect(safeContactUrl('data:text/html,boom')).toBeNull();
|
|
expect(safeContactUrl('mailto:support@example.invalid')).toBe('mailto:support@example.invalid');
|
|
expect(safeContactUrl('https://example.invalid/support')).toBe('https://example.invalid/support');
|
|
});
|
|
|
|
test('payment handler refuses an invoice before wallet or database work when acknowledgement is absent', async () => {
|
|
const previousNodeEnv = process.env.NODE_ENV;
|
|
const previousVersion = process.env.LEGAL_POLICY_VERSION;
|
|
process.env.NODE_ENV = 'production';
|
|
process.env.LEGAL_POLICY_VERSION = 'server-enforcement-v1';
|
|
const emit = jest.fn();
|
|
const createPaymentRequest = jest.fn();
|
|
const handler = new PaymentHandlers({
|
|
io: { to: () => ({ emit }) },
|
|
gameModeManager: {
|
|
...manager({ isTestNetwork: false, network: 'mainnet' }),
|
|
createPaymentRequest,
|
|
isPayoutEnabledForMode: () => false
|
|
},
|
|
walletService: {},
|
|
debugManager: { CONSOLE_LOGGING: false },
|
|
queueManager: {},
|
|
broadcastManager: { sendStatusUpdate: jest.fn() },
|
|
sessionManager: null
|
|
});
|
|
try {
|
|
await handler.handlePaymentRequest({ id: 'socket-1' }, { type: 'single_game' });
|
|
expect(createPaymentRequest).not.toHaveBeenCalled();
|
|
expect(emit).toHaveBeenCalledWith('commerce_ack_required', expect.objectContaining({
|
|
code: 'PAID_ACK_REQUIRED', policyVersion: 'server-enforcement-v1'
|
|
}));
|
|
expect(emit).toHaveBeenCalledWith('payment_error', expect.objectContaining({
|
|
code: 'PAID_ACK_REQUIRED'
|
|
}));
|
|
} finally {
|
|
handler.dispose();
|
|
if (previousNodeEnv === undefined) delete process.env.NODE_ENV;
|
|
else process.env.NODE_ENV = previousNodeEnv;
|
|
if (previousVersion === undefined) delete process.env.LEGAL_POLICY_VERSION;
|
|
else process.env.LEGAL_POLICY_VERSION = previousVersion;
|
|
}
|
|
});
|
|
});
|