Page MenuHomeWickedGov Phorge

tempAccountsOnboardingIPInfoStep.test.js
No OneTemporary

Size
17 KB
Referenced Files
None
Subscribers
None

tempAccountsOnboardingIPInfoStep.test.js

'use strict';
const TempAccountsOnboardingIPInfoStep = require( '../../../modules/ext.checkUser.tempAccountsOnboarding/components/TempAccountsOnboardingIPInfoStep.vue' ),
utils = require( '@vue/test-utils' ),
{ mockApiSaveOption, waitFor } = require( '../utils.js' );
const renderComponent = () => utils.mount( TempAccountsOnboardingIPInfoStep );
/**
* Mocks mw.user.options.get to mock the value of the
* ipinfo-use-agreement preference.
*
* @param {string|0} ipInfoPreferenceValue Value of the ipinfo-use-agreement
* preference for the test
*/
function mockUserOptions( ipInfoPreferenceValue ) {
jest.spyOn( mw.user.options, 'get' ).mockImplementation( ( actualPreferenceName ) => {
if ( actualPreferenceName === 'ipinfo-use-agreement' ) {
return ipInfoPreferenceValue;
} else {
throw new Error(
'Did not expect a call to get the value of ' + actualPreferenceName +
' for mw.user.options.get'
);
}
} );
}
/**
* Mocks mw.storage.session.get to return a specific value when asked for
* the 'mw-checkuser-ipinfo-preference-checked-status' key.
*
* @param {false|'checked'|''|null} value null when no value was set, false when storage is not
* available, empty string when the preference was not checked, string 'checked' when the
* preference was checked.
*/
function mockIPInfoPreferenceCheckedSessionStorageValue( value ) {
jest.spyOn( mw.storage.session, 'get' ).mockImplementation( ( actualStorageKey ) => {
if ( actualStorageKey === 'mw-checkuser-ipinfo-preference-checked-status' ) {
return value;
} else {
throw new Error(
'Did not expect a call to get the value of ' + actualStorageKey +
' for mw.storage.session.get'
);
}
} );
}
/**
* Mocks mw.config.get to mock the value of the wgCheckUserUserHasIPInfoRight JS config.
*
* @param {boolean} userHasIPInfoRight
*/
function mockJSConfig( userHasIPInfoRight ) {
jest.spyOn( mw.config, 'get' ).mockImplementation( ( actualConfigName ) => {
if ( actualConfigName === 'wgCheckUserUserHasIPInfoRight' ) {
return userHasIPInfoRight;
} else {
throw new Error( 'Did not expect a call to get the value of ' + actualConfigName );
}
} );
}
/**
* Performs tests on the step that are the same for all
* starting conditions.
*
* @return {*} The root element for the step
*/
function commonTestRendersCorrectly() {
const wrapper = renderComponent();
expect( wrapper.exists() ).toEqual( true );
// Check the root element exists
const rootElement = wrapper.find(
'.ext-checkuser-temp-account-onboarding-dialog-step'
);
expect( rootElement.exists() ).toEqual( true );
// Check that the image element is present and has the necessary
// class for the image to be placed there.
const imageElement = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-image'
);
expect( imageElement.classes() ).toContain(
'ext-checkuser-image-temp-accounts-onboarding-ip-info'
);
// Expect that the main body is present, and contains the title and content
const mainBodyElement = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-main-body'
);
expect( mainBodyElement.exists() ).toEqual( true );
const titleElement = mainBodyElement.find( 'h5' );
expect( titleElement.exists() ).toEqual( true );
expect( titleElement.text() ).toEqual(
'(checkuser-temporary-accounts-onboarding-dialog-ip-info-step-title)'
);
const contentElement = mainBodyElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-content'
);
expect( contentElement.exists() ).toEqual( true );
expect( contentElement.text() ).toContain(
'(checkuser-temporary-accounts-onboarding-dialog-ip-info-step-content)'
);
return { rootElement: rootElement, wrapper: wrapper };
}
/**
* Gets the IPInfo preference checkbox element
* after checking that it exists.
*
* @param {*} rootElement The root element for the IPInfo step
* @return {*} The IPInfo checkbox element
*/
function getIPInfoPreferenceCheckbox( rootElement ) {
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
expect( ipInfoPreference.exists() ).toEqual( true );
expect( ipInfoPreference.text() ).toContain(
'(ipinfo-preference-use-agreement)'
);
const ipInfoPreferenceCheckbox = ipInfoPreference.find( 'input[type="checkbox"]' );
expect( ipInfoPreferenceCheckbox.exists() ).toEqual( true );
return ipInfoPreferenceCheckbox;
}
/**
* Gets the IPInfo "Save preference" button
* after checking that it exists.
*
* @param {*} rootElement The root element for the IPInfo step
* @return {*} The IPInfo "Save preference" button
*/
function getIPInfoSavePreferenceButton( rootElement ) {
const ipInfoSavePreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-save-preference'
);
expect( ipInfoSavePreference.exists() ).toEqual( true );
const ipInfoSavePreferenceButton = ipInfoSavePreference.find( 'button' );
expect( ipInfoSavePreferenceButton.exists() ).toEqual( true );
return ipInfoSavePreferenceButton;
}
/**
* Expect that the given element contains the given text, or if
* this is not the case then wait for this to be the case.
*
* @param {*} element The element that should contain the text
* @param {string} text The text to search for
*/
async function waitForAndExpectTextToExistInElement( element, text ) {
await waitFor( () => element.text().includes( text ) );
expect( element.text() ).toContain( text );
}
describe( 'IPInfo step temporary accounts onboarding dialog', () => {
afterEach( () => {
jest.restoreAllMocks();
} );
it( 'Renders correctly for when IPInfo preference was already checked', () => {
mockIPInfoPreferenceCheckedSessionStorageValue( null );
mockUserOptions( '1' );
mockJSConfig( true );
const { rootElement } = commonTestRendersCorrectly();
// Expect that the IPInfo preference is not shown if the user has already checked it.
const ipInfoPreferenceSectionTitle = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference-title'
);
expect( ipInfoPreferenceSectionTitle.exists() ).toEqual( false );
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
expect( ipInfoPreference.exists() ).toEqual( false );
} );
it( 'Renders correctly when user does not have "ipinfo" right', () => {
mockIPInfoPreferenceCheckedSessionStorageValue( null );
mockUserOptions( '0' );
mockJSConfig( false );
const { rootElement } = commonTestRendersCorrectly();
// Expect that the IPInfo preference is not shown if the user has already checked it.
const ipInfoPreferenceSectionTitle = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference-title'
);
expect( ipInfoPreferenceSectionTitle.exists() ).toEqual( false );
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
expect( ipInfoPreference.exists() ).toEqual( false );
} );
it( 'Renders correctly when IPInfo preference was checked previously via the dialog', () => {
mockIPInfoPreferenceCheckedSessionStorageValue( 'checked' );
// Mock mw.user.options to say the preference is unchecked, which can happen
// if the user had checked the preference and then moved back to this step.
mockUserOptions( '0' );
mockJSConfig( true );
const { rootElement } = commonTestRendersCorrectly();
// Expect that the IPInfo preference is not shown if the user has
// checked it previously using the dialog
const ipInfoPreferenceSectionTitle = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference-title'
);
expect( ipInfoPreferenceSectionTitle.exists() ).toEqual( false );
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
expect( ipInfoPreference.exists() ).toEqual( false );
} );
it( 'Renders correctly for when IPInfo preference is default value', () => {
mockIPInfoPreferenceCheckedSessionStorageValue( false );
// Test using the integer 0, as the default value is the integer 0 for users which do
// not have a different value for the preference.
mockUserOptions( 0 );
mockJSConfig( true );
const { rootElement } = commonTestRendersCorrectly();
// Check that the preference exists in the step and verify the structure of the preference
// and it's title.
const ipInfoPreferenceSectionTitle = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference-title'
);
expect( ipInfoPreferenceSectionTitle.exists() ).toEqual( true );
expect( ipInfoPreferenceSectionTitle.text() ).toEqual(
'(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-title)'
);
getIPInfoPreferenceCheckbox( rootElement );
getIPInfoSavePreferenceButton( rootElement );
} );
it( 'Does nothing if IPInfo preference checkbox is checked but not saved', async () => {
mockIPInfoPreferenceCheckedSessionStorageValue( '' );
mockUserOptions( '0' );
mockJSConfig( true );
const apiSaveOptionMock = mockApiSaveOption( true );
const { rootElement } = commonTestRendersCorrectly();
const ipInfoPreferenceCheckbox = getIPInfoPreferenceCheckbox( rootElement );
// Check the preference, but check that no API call is made by doing that. The user
// would need to press "Save preference" to make the change
ipInfoPreferenceCheckbox.setChecked();
expect( apiSaveOptionMock ).toHaveBeenCalledTimes( 0 );
} );
it( 'Updates IPInfo preference value after checkbox and submit pressed', async () => {
mockIPInfoPreferenceCheckedSessionStorageValue( '' );
// Test using the string with 0 in it, to test in case the user_properties table has the
// preference specifically marked as unchecked.
mockUserOptions( '0' );
mockJSConfig( true );
const apiSaveOptionMock = mockApiSaveOption( true );
const { rootElement, wrapper } = commonTestRendersCorrectly();
const ipInfoPreferenceCheckbox = getIPInfoPreferenceCheckbox( rootElement );
const ipInfoSavePreferenceButton = getIPInfoSavePreferenceButton( rootElement );
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
// Check the preference checkbox and then press the "Save preference" button
// and check that an API call is made to set the preference.
ipInfoPreferenceCheckbox.setChecked();
await ipInfoSavePreferenceButton.trigger( 'click' );
expect( apiSaveOptionMock ).toHaveBeenLastCalledWith( 'ipinfo-use-agreement', 1 );
// Expect that the preference checkbox has a success message shown to indicate the
// preference was updated successfully.
await waitForAndExpectTextToExistInElement(
ipInfoPreference, '(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-success)'
);
// Check that if the preference saved, the user can move forward to another
// step and/or close the dialog.
expect( wrapper.vm.canMoveToAnotherStep() ).toEqual( true );
expect( wrapper.vm.shouldWarnBeforeClosingDialog() ).toEqual( false );
// Uncheck the preference
ipInfoPreferenceCheckbox.setChecked( false );
// Check that the success message disappears when the preference is unchecked
await waitFor( () => !ipInfoPreference.text().includes( '(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-success)' ) );
expect( ipInfoPreference.text() ).not.toContain(
'(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-success)'
);
// Save the change to the preference and then check that this has caused
// the API to be called.
await ipInfoSavePreferenceButton.trigger( 'click' );
// Expect that the preference checkbox has a success message shown to indicate the
// preference was updated successfully.
await waitForAndExpectTextToExistInElement(
ipInfoPreference, '(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-success)'
);
expect( apiSaveOptionMock ).toHaveBeenLastCalledWith( 'ipinfo-use-agreement', 0 );
} );
it( 'Prevents step move if IPInfo preference checked but not saved', async () => {
mockIPInfoPreferenceCheckedSessionStorageValue( '' );
mockUserOptions( 0 );
mockJSConfig( true );
const { rootElement, wrapper } = commonTestRendersCorrectly();
const ipInfoPreferenceCheckbox = getIPInfoPreferenceCheckbox( rootElement );
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
// Check the preference checkbox, but don't save the preference using the button
ipInfoPreferenceCheckbox.setChecked();
// Call the canMoveToAnotherStep() method and expect that it returns false, to
// indicate that moving to another step is not allowed yet.
expect( wrapper.vm.canMoveToAnotherStep() ).toEqual( false );
// Expect that the preference checkbox has a warning in the UI indicating to the
// user to save the preference before proceeding to the next step.
await waitForAndExpectTextToExistInElement(
ipInfoPreference, '(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-warning)'
);
} );
it( 'Prevents dialog close if IPInfo preference checked but not saved', async () => {
mockIPInfoPreferenceCheckedSessionStorageValue( '' );
mockUserOptions( 0 );
mockJSConfig( true );
const { rootElement, wrapper } = commonTestRendersCorrectly();
const ipInfoPreferenceCheckbox = getIPInfoPreferenceCheckbox( rootElement );
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
// Check the preference checkbox, but don't save the preference using the button
ipInfoPreferenceCheckbox.setChecked();
// Call the shouldWarnBeforeClosingDialog() method and expect that it returns true, to
// indicate that closing the dialog is not allowed at the moment.
expect( wrapper.vm.shouldWarnBeforeClosingDialog() ).toEqual( true );
// Expect that the preference checkbox has a warning in the UI indicating to the
// user to save the preference before closing the dialog
await waitForAndExpectTextToExistInElement(
ipInfoPreference, '(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-warning)'
);
} );
it( 'Displays error message if IPInfo preference check failed', async () => {
mockIPInfoPreferenceCheckedSessionStorageValue( '' );
mockUserOptions( '0' );
mockJSConfig( true );
const apiSaveOptionMock = mockApiSaveOption(
false, { error: { info: 'Wiki is in read only mode' } }
);
const { rootElement, wrapper } = commonTestRendersCorrectly();
const ipInfoPreferenceCheckbox = getIPInfoPreferenceCheckbox( rootElement );
const ipInfoSavePreferenceButton = getIPInfoSavePreferenceButton( rootElement );
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
// Turn on the preference and click the "Save preference" button
ipInfoPreferenceCheckbox.setChecked();
ipInfoSavePreferenceButton.trigger( 'click' );
// Expect that an error appears indicating the preference update failed.
await waitForAndExpectTextToExistInElement(
ipInfoPreference,
'(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-error' +
', Wiki is in read only mode)'
);
expect( apiSaveOptionMock ).toHaveBeenLastCalledWith( 'ipinfo-use-agreement', 1 );
// Check that if the preference failed to save, the user can still move
// forward to another step and/or close the dialog.
expect( wrapper.vm.canMoveToAnotherStep() ).toEqual( true );
expect( wrapper.vm.shouldWarnBeforeClosingDialog() ).toEqual( false );
} );
it( 'Only submits one preference change on race condition', async () => {
mockIPInfoPreferenceCheckedSessionStorageValue( '' );
mockUserOptions( '0' );
mockJSConfig( true );
// Mock the api.saveOption() method to only resolve when we want it to
// so that we can test race-condition handling.
const apiSaveOptionMock = jest.fn();
const promisesToResolve = [];
apiSaveOptionMock.mockReturnValue( new Promise( ( resolve ) => {
promisesToResolve.push( resolve );
} ) );
jest.spyOn( mw, 'Api' ).mockImplementation( () => ( {
saveOption: apiSaveOptionMock
} ) );
const { rootElement } = commonTestRendersCorrectly();
const ipInfoPreferenceCheckbox = getIPInfoPreferenceCheckbox( rootElement );
const ipInfoSavePreferenceButton = getIPInfoSavePreferenceButton( rootElement );
const ipInfoPreference = rootElement.find(
'.ext-checkuser-temp-account-onboarding-dialog-ip-info-preference'
);
// Turn on the preference and click the "Save preference" button a couple of times
ipInfoPreferenceCheckbox.setChecked();
ipInfoSavePreferenceButton.trigger( 'click' );
ipInfoSavePreferenceButton.trigger( 'click' );
ipInfoSavePreferenceButton.trigger( 'click' );
ipInfoSavePreferenceButton.trigger( 'click' );
// Expect that api.saveOption has only been called once, as the first call is still
// not been resolved.
expect( apiSaveOptionMock ).toHaveBeenLastCalledWith( 'ipinfo-use-agreement', 1 );
expect( promisesToResolve ).toHaveLength( 1 );
promisesToResolve.forEach( ( promiseResolver ) => {
promiseResolver( { options: 'success' } );
} );
// Now that the promise is resolved, expect it the success message to appear.
await waitForAndExpectTextToExistInElement(
ipInfoPreference, '(checkuser-temporary-accounts-onboarding-dialog-ip-info-preference-success)'
);
} );
} );

File Metadata

Mime Type
text/plain
Expires
Oct 4 2026, 02:12 (4 w, 5 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ce/2b/f21fff06a2648aa56d2ae194df9a
Default Alt Text
tempAccountsOnboardingIPInfoStep.test.js (17 KB)

Event Timeline