Page MenuHomeWickedGov Phorge

UserCardMenu.test.js
No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None

UserCardMenu.test.js

'use strict';
const { shallowMount } = require( 'vue-test-utils' );
const UserCardMenu = require( 'ext.checkUser.userInfoCard/modules/ext.checkUser.userInfoCard/components/UserCardMenu.vue' );
QUnit.module( 'ext.checkUser.userInfoCard.UserCardMenu', QUnit.newMwEnvironment( {
beforeEach: function () {
this.server = this.sandbox.useFakeServer();
this.server.respondImmediately = true;
// Stub mw.msg
this.sandbox.stub( mw, 'msg' ).callsFake( ( key, ...args ) => {
let returnValue = '(' + key;
if ( args.length !== 0 ) {
returnValue += ': ' + args.join( ', ' );
}
return returnValue + ')';
} );
// Stub mw.Title.makeTitle
this.sandbox.stub( mw.Title, 'makeTitle' ).callsFake( ( namespace, title ) => ( {
getUrl: ( query ) => {
let url = `/${ namespace }/${ title }`;
if ( query ) {
const params = Object.entries( query )
.map( ( [ key, value ] ) => `${ key }=${ value }` )
.join( '&' );
url += `?${ params }`;
}
return url;
},
getPrefixedText: () => {
const nsText = namespace === 0 ? '' : `Namespace${ namespace }:`;
return `${ nsText }${ title }`;
}
} ) );
// Force permission configs
mw.config.set( 'wgCheckUserCanPerformCheckUser', true );
mw.config.set( 'wgCheckUserCanBlock', true );
},
afterEach: function () {
this.server.restore();
}
} ) );
// Reusable mount helper
function mountComponent( props = {} ) {
return shallowMount( UserCardMenu, {
propsData: {
userId: '123',
username: 'TestUser',
gender: 'female',
specialCentralAuthUrl: 'https://example.com/wiki/Special:CentralAuth/TestUser',
...props
}
} );
}
QUnit.test( 'renders correctly with default props', ( assert ) => {
const wrapper = mountComponent();
assert.true( wrapper.exists(), 'Component renders' );
} );
QUnit.test( 'computes menu items correctly with all permissions', ( assert ) => {
const wrapper = mountComponent();
const menuItems = wrapper.vm.menuItems;
assert.strictEqual( menuItems.length, 7, 'Menu has 7 items with all permissions' );
assert.strictEqual(
menuItems[ 0 ].value,
'view-contributions',
'First item is view-contributions'
);
assert.strictEqual(
menuItems[ 0 ].label,
'(checkuser-userinfocard-menu-view-contributions: female)',
'Contributions label is correct'
);
assert.strictEqual(
menuItems[ 0 ].url,
'/-1/Contributions/TestUser',
'Contributions link is correct'
);
assert.strictEqual(
menuItems[ 1 ].value,
'view-global-account',
'Second item is view-global-account'
);
assert.strictEqual(
menuItems[ 1 ].label,
'(checkuser-userinfocard-menu-view-global-account: female)',
'Global account label is correct'
);
assert.strictEqual(
menuItems[ 1 ].url,
'https://example.com/wiki/Special:CentralAuth/TestUser',
'Global account link is correct'
);
assert.strictEqual( menuItems[ 2 ].value, 'toggle-watchlist', 'Third item is toggle-watchlist' );
assert.strictEqual(
menuItems[ 2 ].label,
'(checkuser-userinfocard-menu-add-to-watchlist: female)',
'Watchlist label is correct'
);
assert.strictEqual( menuItems[ 3 ].value, 'check-ip', 'Fourth item is check-ip' );
assert.strictEqual(
menuItems[ 3 ].label,
'(checkuser-userinfocard-menu-check-ip: female)',
'Check IP label is correct'
);
assert.strictEqual(
menuItems[ 3 ].url,
'/-1/CheckUser?user=TestUser',
'Check IP link is correct'
);
assert.strictEqual( menuItems[ 4 ].value, 'block-user', 'Fifth item is block-user' );
assert.strictEqual(
menuItems[ 4 ].label,
'(checkuser-userinfocard-menu-block-user: female)',
'Block user label is correct'
);
assert.strictEqual( menuItems[ 4 ].url, '/-1/Block/TestUser', 'Block user link is correct' );
assert.strictEqual( menuItems[ 5 ].value, 'provide-feedback', 'Sixth item is provide-feedback' );
assert.strictEqual(
menuItems[ 5 ].label,
'(checkuser-userinfocard-menu-provide-feedback)',
'Provide feedback label is correct'
);
assert.strictEqual(
menuItems[ 5 ].url,
'https://www.mediawiki.org/wiki/Talk:Trust_and_Safety_Product/Anti-abuse_signals/User_Info',
'Provide feedback link is correct'
);
assert.strictEqual( menuItems[ 6 ].value, 'turn-off', 'Seventh item is turn-off' );
assert.strictEqual(
menuItems[ 6 ].label,
'(checkuser-userinfocard-menu-turn-off)',
'Turn off label is correct'
);
assert.strictEqual(
menuItems[ 6 ].url,
'/-1/Preferences#mw-prefsection-rendering-advancedrendering',
'Turn off link is correct'
);
} );
QUnit.test( 'computes menu items correctly with no permissions', ( assert ) => {
// Mock permission configs - default to false for tests
mw.config.set( 'wgCheckUserCanPerformCheckUser', false );
mw.config.set( 'wgCheckUserCanBlock', false );
const wrapper = mountComponent();
const menuItems = wrapper.vm.menuItems;
assert.strictEqual( menuItems.length, 5, 'Menu has 5 items with no permissions' );
// Check that the basic items are still there
assert.strictEqual( menuItems[ 0 ].value, 'view-contributions', 'First item is view-contributions' );
assert.strictEqual( menuItems[ 1 ].value, 'view-global-account', 'Second item is view-global-account' );
assert.strictEqual( menuItems[ 2 ].value, 'toggle-watchlist', 'Third item is toggle-watchlist' );
assert.strictEqual( menuItems[ 3 ].value, 'provide-feedback', 'Fourth item is provide-feedback' );
assert.strictEqual( menuItems[ 4 ].value, 'turn-off', 'Fifth item is turn-off' );
// Check that permission-based items are not present
const checkIpItem = menuItems.find( ( item ) => item.value === 'check-ip' );
assert.strictEqual( checkIpItem, undefined, 'check-ip item is not present when permission is not granted' );
const blockUserItem = menuItems.find( ( item ) => item.value === 'block-user' );
assert.strictEqual( blockUserItem, undefined, 'block-user item is not present when permission is not granted' );
} );
QUnit.test( 'computes menu items correctly with only check-ip permission', ( assert ) => {
// Mock permission configs - default to true for tests
mw.config.set( 'wgCheckUserCanPerformCheckUser', true );
mw.config.set( 'wgCheckUserCanBlock', false );
const wrapper = mountComponent();
const menuItems = wrapper.vm.menuItems;
assert.strictEqual( menuItems.length, 6, 'Menu has 6 items with only check-ip permission' );
// Check that the check-ip item is present
const checkIpItem = menuItems.find( ( item ) => item.value === 'check-ip' );
assert.notStrictEqual( checkIpItem, undefined, 'check-ip item is present when permission is granted' );
// Check that the block-user item is not present
const blockUserItem = menuItems.find( ( item ) => item.value === 'block-user' );
assert.strictEqual( blockUserItem, undefined, 'block-user item is not present when permission is not granted' );
} );
QUnit.test( 'computes menu items correctly with only block-user permission', ( assert ) => {
// Mock permission configs - default to true for tests
mw.config.set( 'wgCheckUserCanPerformCheckUser', false );
mw.config.set( 'wgCheckUserCanBlock', true );
const wrapper = mountComponent();
const menuItems = wrapper.vm.menuItems;
assert.strictEqual( menuItems.length, 6, 'Menu has 6 items with only block-user permission' );
// Check that the check-ip item is not present
const checkIpItem = menuItems.find( ( item ) => item.value === 'check-ip' );
assert.strictEqual( checkIpItem, undefined, 'check-ip item is not present when permission is not granted' );
// Check that the block-user item is present
const blockUserItem = menuItems.find( ( item ) => item.value === 'block-user' );
assert.notStrictEqual( blockUserItem, undefined, 'block-user item is present when permission is granted' );
} );
QUnit.test( 'watchlist label changes based on initial state', ( assert ) => {
const wrapper = mountComponent( { userPageWatched: true, gender: 'male' } );
const menuItems = wrapper.vm.menuItems;
assert.strictEqual(
menuItems[ 2 ].label,
'(checkuser-userinfocard-menu-remove-from-watchlist: male)',
'Watchlist label is correct'
);
} );
QUnit.test( 'shows XTools link when configured', ( assert ) => {
mw.config.set( 'wgCheckUserUserInfoCardShowXToolsLink', true );
mw.config.set( 'wgDBname', 'enwiki' );
const wrapper = mountComponent( { username: 'TestUser' } );
const menuItems = wrapper.vm.menuItems;
const xToolsItem = menuItems.find( ( item ) => item.value === 'view-xtools' );
assert.notStrictEqual( xToolsItem, undefined, 'view-xtools item is present' );
assert.strictEqual(
xToolsItem.url,
'https://xtools.wmcloud.org/ec/enwiki/TestUser',
'XTools link is correct'
);
} );
QUnit.test( 'hides XTools link when not configured', ( assert ) => {
mw.config.set( 'wgCheckUserUserInfoCardShowXToolsLink', false );
const wrapper = mountComponent();
const menuItems = wrapper.vm.menuItems;
const xToolsItem = menuItems.find( ( item ) => item.value === 'view-xtools' );
assert.strictEqual( xToolsItem, undefined, 'view-xtools item is not present' );
} );
// TODO: T386440 - Fix the test and remove the skip
// This test fails when running in conjunction with the other test components in this folder.
// When running this test file alone, this test is passing.
QUnit.test.skip( 'logs an event when onMenuSelect is called', function ( assert ) {
mw.config.set( 'CheckUserEnableUserInfoCardInstrumentation', true );
this.sandbox.stub( mw.user, 'sessionId' ).returns( 'test-session-id' );
this.sandbox.stub( mw.user, 'getId' ).returns( 123 );
const submitInteractionStub = this.sandbox.stub();
submitInteractionStub.respondImmediately = true;
const instrumentStub = { submitInteraction: submitInteractionStub };
this.sandbox.stub( mw.eventLog, 'newInstrument' ).returns( instrumentStub );
const wrapper = mountComponent();
// Call with a fake item so it doesn't trigger window navigation
wrapper.vm.onMenuSelect( 'a-fake-item' );
assert.strictEqual( submitInteractionStub.callCount, 1, 'submitInteraction is called once' );
assert.strictEqual(
submitInteractionStub.firstCall.args[ 0 ],
'link_click',
'First argument is "link_click"'
);
const interactionData = submitInteractionStub.firstCall.args[ 1 ];
assert.strictEqual(
interactionData.funnel_entry_token,
'test-session-id',
'Includes session token in interaction data'
);
assert.strictEqual(
interactionData.action_subtype,
'a-fake-item',
'Includes correct subType in interaction data'
);
assert.strictEqual(
interactionData.action_source,
'card_menu',
'Includes correct source in interaction data'
);
} );

File Metadata

Mime Type
text/plain
Expires
Aug 16 2026, 12:19 (11 w, 6 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
5c/0f/2cc208d8ffe40cf20aae76991f4d
Default Alt Text
UserCardMenu.test.js (10 KB)

Event Timeline