'use strict'; const initOnHook = require( 'ext.checkUser.tempAccounts/initOnHook.js' ); const { makeTempUserLink, waitUntilElementCount } = require( './utils.js' ); const Utils = require( 'ext.checkUser.tempAccounts/ipRevealUtils.js' ); const originalSetAutoRevealStatus = Utils.setAutoRevealStatus; let server; QUnit.module( 'ext.checkUser.tempAccounts.initOnHook', QUnit.newMwEnvironment( { beforeEach: function () { this.server = this.sandbox.useFakeServer(); this.server.respondImmediately = true; server = this.server; }, afterEach: function () { server.restore(); Utils.setAutoRevealStatus = originalSetAutoRevealStatus; }, config: { // Prevent initOnLoad.js from running automatically and then // calling enableMultiReveal on the document. wgCanonicalSpecialPageName: 'CheckUser', wgCheckUserTemporaryAccountMaxAge: 1500 } } ) ); QUnit.test( 'Test initOnHook when there are no temporary account user links on load', ( assert ) => { // eslint-disable-next-line no-jquery/no-global-selector const $qunitFixture = $( '#qunit-fixture' ); assert.strictEqual( $qunitFixture.find( '.ext-checkuser-tempaccount-reveal-ip-button' ).length, 0, 'No IP reveal links before initOnHook call' ); // Call initOnHook with the QUnit fixture as the document root initOnHook( $qunitFixture ); assert.strictEqual( $qunitFixture.find( '.ext-checkuser-tempaccount-reveal-ip-button' ).length, 0, 'No IP reveal links after initOnHook call' ); } ); QUnit.test( 'Test initOnHook when temporary account links added after load', ( assert ) => { // eslint-disable-next-line no-jquery/no-global-selector const $qunitFixture = $( '#qunit-fixture' ); // Call initOnHook with the QUnit fixture as the document root initOnHook( $qunitFixture ); // Now add the temporary account links to the page and fire wikipage.content // on the newly added content. const $revisionLine = $( '
' ).attr( 'data-mw-revid', 1 ); $qunitFixture.append( $revisionLine ); // Add the temporary account username link for the revision line const $tempAccountUserLink = makeTempUserLink( '~12' ); $revisionLine.append( $tempAccountUserLink ); // Fire wikipage.content on the newly added content mw.hook( 'wikipage.content' ).fire( $qunitFixture ); // Verify that a "Show IP" button has been added next to the newly added temporary account link. assert.strictEqual( // eslint-disable-next-line no-jquery/no-class-state $tempAccountUserLink.next().hasClass( 'ext-checkuser-tempaccount-reveal-ip-button' ), true, 'Button is after temp user link added with wikipage.content hook fired' ); } ); /** * Sets up the document for a test where some temporary account user links are * automatically revealed, and then fires the "wikipage.content" hook on the * newly added content. * * @return {{ * temporaryAccountUserLinksThatAreAutomaticallyRevealed: jQuery[], * temporaryAccountUserLinks: jQuery[] * }} The list of jQuery elements for the temporary account user links that were * added to the document, split into two by those which are automatically revealed * and those which are not. */ function setUpDocumentForTest() { // eslint-disable-next-line no-jquery/no-global-selector const $qunitFixture = $( '#qunit-fixture' ); const temporaryAccountUserLinks = []; const temporaryAccountUserLinksThatAreAutomaticallyRevealed = []; // Add some testing revision lines const revisionLines = { 1: '~1', 2: '~1', 3: '~2' }; Object.entries( revisionLines ).forEach( ( [ revId, username ] ) => { const $revisionLine = $( '
' ).attr( 'data-mw-revid', revId ); $qunitFixture.append( $revisionLine ); // Add the temporary account username link for the revision line const $tempAccountUserLink = makeTempUserLink( username ); $revisionLine.append( $tempAccountUserLink ); if ( Utils.getRevealedStatus( username ) ) { temporaryAccountUserLinksThatAreAutomaticallyRevealed.push( $tempAccountUserLink ); } else { temporaryAccountUserLinks.push( $tempAccountUserLink ); } } ); // Fire wikipage.content on the QUnit test fixture mw.hook( 'wikipage.content' ).fire( $qunitFixture ); return { temporaryAccountUserLinks, temporaryAccountUserLinksThatAreAutomaticallyRevealed }; } QUnit.test( 'Test initOnHook with recently revealed temp user links added after load', ( assert ) => { // Prevent the test being very slow if the wait for condition fails. assert.timeout( 1000 ); // This assumes that the API request is for the revision API, however, this should occur // because only revision related temporary account "Show IP" buttons should exist in // the page. server.respond( ( request ) => { const response = request.url.endsWith( '/checkuser/v0/batch-temporaryaccount' ) ? { '~1': { revIps: { 1: '127.0.0.1', 2: '127.0.0.1' }, logIps: null, lastUsedIp: null } } : { ips: { 1: '127.0.0.1', 2: '127.0.0.1' } }; request.respond( 200, { 'Content-Type': 'application/json' }, JSON.stringify( response ) ); } ); // eslint-disable-next-line no-jquery/no-global-selector const $qunitFixture = $( '#qunit-fixture' ); // Call initOnHook with the QUnit fixture as the document root initOnHook( $qunitFixture ); // Mark that the ~1 temporary account username has been revealed previously, and so // should be automatically revealed when the page loads. Utils.setRevealedStatus( '~1' ); // Add the new content for the test. const { temporaryAccountUserLinks, temporaryAccountUserLinksThatAreAutomaticallyRevealed } = setUpDocumentForTest(); // Wait until there are three IP reveal buttons const done = assert.async(); waitUntilElementCount( '.ext-checkuser-tempaccount-reveal-ip', temporaryAccountUserLinksThatAreAutomaticallyRevealed.length ).then( () => { // Verify that the Show IP button was added for all temporary user links that should not be // automatically revealed on load. temporaryAccountUserLinks.forEach( ( $element ) => { assert.strictEqual( // eslint-disable-next-line no-jquery/no-class-state $element.next().hasClass( 'ext-checkuser-tempaccount-reveal-ip-button' ), true, 'Button is after temp user link for non-recently revealed temporary account' ); } ); // Verify that the relevant IP is shown for the temporary account user links that should be // automatically revealed on load. temporaryAccountUserLinksThatAreAutomaticallyRevealed.forEach( ( $element ) => { assert.strictEqual( $element.next().text(), '127.0.0.1', 'IP is after temporary account user link for recently revealed temporary account' ); } ); // Remove the cookie after the test to avoid breaking other tests. mw.storage.remove( 'mw-checkuser-temp-~1' ); done(); } ); } ); QUnit.test( 'Test initOnHook when IP auto-reveal mode is toggled on and off', ( assert ) => { // Prevent the test being very slow if the wait for condition fails. assert.timeout( 1000 ); // Handle requests to the temporary account IP lookup APIs responding with // mock data and a 200 HTTP status code. server.respond( ( request ) => { const response = request.url.endsWith( '/checkuser/v0/batch-temporaryaccount' ) ? { '~1': { revIps: { 1: '127.0.0.1', 2: '127.0.0.1' }, logIps: null, lastUsedIp: null }, '~2': { revIps: { 3: '127.0.0.1' }, logIps: null, lastUsedIp: null }, autoReveal: true } : {}; request.respond( 200, { 'Content-Type': 'application/json' }, JSON.stringify( response ) ); } ); // eslint-disable-next-line no-jquery/no-global-selector const $qunitFixture = $( '#qunit-fixture' ); // Call initOnHook with the QUnit fixture as the document root initOnHook( $qunitFixture ); // Turn on IP auto-reveal mode. const expiry = Date.now() + 3600000; Utils.getAutoRevealStatus = function () { return $.Deferred().resolve( expiry ); }; // Add the new content for the test. const { temporaryAccountUserLinks } = setUpDocumentForTest(); // Wait until there are IP reveal buttons are added const done = assert.async(); waitUntilElementCount( '.ext-checkuser-tempaccount-reveal-ip', temporaryAccountUserLinks.length ).then( () => { // Verify that the relevant IP is shown for the temporary account user links. temporaryAccountUserLinks.forEach( ( $element ) => { assert.strictEqual( $element.next().text(), '127.0.0.1', 'IP is after temporary account user link when IP auto-reveal mode is on' ); } ); // Turn off IP auto-reveal mode. Utils.getAutoRevealStatus = function () { return $.Deferred().resolve( false ); }; initOnHook( $qunitFixture ); // Verify that the IPs are hidden and the Show IP button is displayed. temporaryAccountUserLinks.forEach( ( $element ) => { assert.strictEqual( // eslint-disable-next-line no-jquery/no-class-state $element.next().hasClass( 'ext-checkuser-tempaccount-reveal-ip-button' ), true, 'Show IP button is after temporary account user link when IP auto-reveal mode is off' ); } ); done(); } ); } );