'use strict';
const { shallowMount, mount } = require( 'vue-test-utils' );
const InfoRowWithLinks = require( 'ext.checkUser.userInfoCard/modules/ext.checkUser.userInfoCard/components/InfoRowWithLinks.vue' );
QUnit.module( 'ext.checkUser.userInfoCard.InfoRowWithLinks', QUnit.newMwEnvironment( {
beforeEach: function () {
// Mock mw.message to return a mock object with parse method
this.sandbox.stub( mw, 'message' ).callsFake( ( key, ...args ) => ( {
parse: () => {
// Simple mock implementation that includes the arguments
if ( args.length === 2 ) {
// Two arguments (main and suffix)
return `${ key } with ${ args[ 0 ].get( 0 ).outerHTML } and ${ args[ 1 ].get( 0 ).outerHTML }`;
} else if ( args.length === 1 ) {
// One argument (main only)
return `${ key } with ${ args[ 0 ].get( 0 ).outerHTML }`;
}
return key;
}
} ) );
mw.config.set( 'CheckUserEnableUserInfoCardInstrumentation', false );
}
} ) );
// Reusable mount helper
function mountComponent( props = {} ) {
return shallowMount( InfoRowWithLinks, {
propsData: {
messageKey: 'checkuser-userinfocard-active-blocks',
mainValue: 'Test Value',
...props
}
} );
}
QUnit.test( 'formattedMessage computed property creates correct HTML for main value only', ( assert ) => {
const wrapper = mountComponent( {
messageKey: 'checkuser-userinfocard-global-edits',
mainValue: 'Test Value',
mainLink: 'https://example.com'
} );
const formattedMessage = wrapper.vm.formattedMessage;
assert.true(
formattedMessage.includes( 'checkuser-userinfocard-global-edits' ),
'Formatted message includes message key'
);
assert.true(
formattedMessage.includes( 'Test Value' ),
'Formatted message includes main value'
);
assert.true(
formattedMessage.includes( 'href="https://example.com"' ),
'Formatted message includes main link'
);
} );
QUnit.test( 'formattedMessage computed property creates correct HTML for main and suffix values', ( assert ) => {
const wrapper = mountComponent( {
messageKey: 'checkuser-userinfocard-active-blocks',
mainValue: 'Main Value',
mainLink: 'https://example.com',
suffixValue: 'Suffix Value',
suffixLink: 'https://example.org'
} );
const formattedMessage = wrapper.vm.formattedMessage;
assert.true(
formattedMessage.includes( 'checkuser-userinfocard-active-blocks' ),
'Formatted message includes message key'
);
assert.true(
formattedMessage.includes( 'Main Value' ),
'Formatted message includes main value'
);
assert.true(
formattedMessage.includes( 'Suffix Value' ),
'Formatted message includes suffix value'
);
assert.true(
formattedMessage.includes( 'href="https://example.com"' ),
'Formatted message includes main link'
);
assert.true(
formattedMessage.includes( 'href="https://example.org"' ),
'Formatted message includes suffix link'
);
} );
QUnit.test( 'creates span instead of link when no URL is provided', ( assert ) => {
const wrapper = mountComponent( {
messageKey: 'checkuser-userinfocard-global-edits',
mainValue: 'Test Value'
// No mainLink provided
} );
const formattedMessage = wrapper.vm.formattedMessage;
assert.true(
formattedMessage.includes( 'Test Value' ),
'Creates span when no link is provided'
);
assert.false(
formattedMessage.includes( ' {
const testCases = [ '', null, undefined ];
testCases.forEach( ( suffixValue ) => {
const wrapper = mountComponent( {
messageKey: 'checkuser-userinfocard-active-blocks',
mainValue: 'Main Value',
suffixValue: suffixValue
} );
const formattedMessage = wrapper.vm.formattedMessage;
// Should only have one argument (main) passed to mw.message
assert.true(
formattedMessage.includes( 'checkuser-userinfocard-active-blocks with' ),
`Formatted message is created for suffixValue: ${ suffixValue }`
);
} );
} );
QUnit.test( 'handles numeric values correctly', ( assert ) => {
const wrapper = mountComponent( {
messageKey: 'checkuser-userinfocard-active-blocks',
mainValue: 42,
suffixValue: 123
} );
const formattedMessage = wrapper.vm.formattedMessage;
assert.true(
formattedMessage.includes( '42' ),
'Numeric main value is converted to string'
);
assert.true(
formattedMessage.includes( '123' ),
'Numeric suffix value is converted to string'
);
} );
QUnit.test( 'renders formatted message using v-html', ( assert ) => {
const wrapper = mount( InfoRowWithLinks, {
propsData: {
messageKey: 'checkuser-userinfocard-global-edits',
mainValue: 'Test Value'
}
} );
const span = wrapper.find( 'span' );
assert.true( span.exists(), 'Span element exists for v-html content' );
// The actual HTML content is set via v-html, so we check the computed property
assert.true(
wrapper.vm.formattedMessage.includes( 'Test Value' ),
'Formatted message contains expected content'
);
} );
// 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 onLinkClick 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().resolves();
submitInteractionStub.respondImmediately = true;
const instrumentStub = { submitInteraction: submitInteractionStub };
this.sandbox.stub( mw.eventLog, 'newInstrument' ).returns( instrumentStub );
const wrapper = mountComponent( {
mainLinkLogId: 'main_link_id'
} );
wrapper.vm.onLinkClick( 'main_link_id' );
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,
'main_link_id',
'Includes correct subType in interaction data'
);
assert.strictEqual(
interactionData.action_source,
'card_body',
'Includes correct source in interaction data'
);
} );