Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/__mocks__/electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ BrowserWindow.prototype.isFullScreen = jest.fn( () => false );

const mockWebContents = {
on: jest.fn(),
once: jest.fn(),
send: jest.fn(),
isDestroyed: jest.fn( () => false ),
};
Expand All @@ -63,6 +64,10 @@ BrowserWindow.prototype.emit = jest.fn( ( event: string, ...args: any[] ) => {
handlers.forEach( ( handler ) => handler( ...args ) );
} );

export const dialog = {
showMessageBox: jest.fn(),
};

export const Menu = {
buildFromTemplate: jest.fn(),
setApplicationMenu: jest.fn(),
Expand Down
5 changes: 0 additions & 5 deletions src/components/onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,6 @@ export default function Onboarding() {
event.preventDefault();
// Save current app version to prevent What's New from showing for new users
await saveLastSeenVersion( window.appGlobals.appVersion );
try {
await getIpcApi().promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );
} catch ( error ) {
console.error( error );
}

try {
await handleAddSiteClick();
Expand Down
300 changes: 300 additions & 0 deletions src/lib/tests/windows-helpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
/**
* @jest-environment node
*/
import { app, dialog, BrowserWindow } from 'electron';
import { getMainWindow } from 'src/main-window';
import { loadUserData, updateAppdata } from 'src/storage/user-data';
import { promptWindowsSpeedUpSites } from '../windows-helpers';

jest.mock( 'electron' );
jest.mock( 'src/main-window' );
jest.mock( 'src/storage/user-data' );
jest.mock( '@vscode/sudo-prompt', () => ( {
exec: jest.fn( ( _command, _options, callback ) => {
callback( null );
} ),
} ) );

const mockLoadUserData = loadUserData as jest.MockedFunction< typeof loadUserData >;
const mockUpdateAppdata = updateAppdata as jest.MockedFunction< typeof updateAppdata >;
const mockGetMainWindow = getMainWindow as jest.MockedFunction< typeof getMainWindow >;
const mockAppGetVersion = app.getVersion as jest.MockedFunction< typeof app.getVersion >;
const mockDialogShowMessageBox = dialog.showMessageBox as jest.MockedFunction<
typeof dialog.showMessageBox
>;

const currentVersion = '1.2.3';
const originalPlatform = process.platform;

afterEach( () => {
jest.clearAllMocks();
Object.defineProperty( process, 'platform', {
value: originalPlatform,
} );
} );

describe( 'promptWindowsSpeedUpSites', () => {
beforeEach( () => {
mockGetMainWindow.mockResolvedValue( new BrowserWindow() );
mockAppGetVersion.mockReturnValue( currentVersion );

// Mock platform as Windows
Object.defineProperty( process, 'platform', {
value: 'win32',
} );
} );

describe( 'platform checks', () => {
it( 'should return early on non-Windows platforms', async () => {
Object.defineProperty( process, 'platform', { value: 'darwin' } );

mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: false } );

expect( mockDialogShowMessageBox ).not.toHaveBeenCalled();
} );

it( 'should show prompt on Windows platform', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: false } );

expect( mockDialogShowMessageBox ).toHaveBeenCalled();
} );
} );

describe( 'version tracking', () => {
it( 'should show prompt when no previous response exists', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockDialogShowMessageBox ).toHaveBeenCalled();
} );

it( 'should skip prompt when user said "no" to the current version', async () => {
mockLoadUserData.mockResolvedValue( {
sites: [],
snapshots: [],
promptWindowsSpeedUpResult: {
response: 'no',
appVersion: currentVersion,
dontAskAgain: false,
},
} );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockDialogShowMessageBox ).not.toHaveBeenCalled();
} );

it( 'should show prompt again when user said "no" to a previous version', async () => {
mockLoadUserData.mockResolvedValue( {
sites: [],
snapshots: [],
promptWindowsSpeedUpResult: {
response: 'no',
appVersion: '1.2.2', // Previous version
dontAskAgain: false,
},
} );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockDialogShowMessageBox ).toHaveBeenCalled();
} );

it( 'should skip prompt when user said "yes" regardless of version', async () => {
mockLoadUserData.mockResolvedValue( {
sites: [],
snapshots: [],
promptWindowsSpeedUpResult: {
response: 'yes',
appVersion: '1.2.2', // Previous version
dontAskAgain: false,
},
} );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockDialogShowMessageBox ).not.toHaveBeenCalled();
} );

it( 'should always show prompt when skipIfAlreadyPrompted is false', async () => {
mockLoadUserData.mockResolvedValue( {
sites: [],
snapshots: [],
promptWindowsSpeedUpResult: {
response: 'no',
appVersion: currentVersion,
dontAskAgain: false,
},
} );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: false } );

expect( mockDialogShowMessageBox ).toHaveBeenCalled();
} );
} );

describe( 'legacy format handling', () => {
it( 'should handle legacy string format "yes" and skip prompt', async () => {
mockLoadUserData.mockResolvedValue( {
sites: [],
snapshots: [],
// @ts-expect-error - Testing legacy string format for backward compatibility
promptWindowsSpeedUpResult: 'yes',
} );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockDialogShowMessageBox ).not.toHaveBeenCalled();
} );

it( 'should handle legacy string format "no" and show prompt', async () => {
mockLoadUserData.mockResolvedValue( {
sites: [],
snapshots: [],
// @ts-expect-error - Testing legacy string format for backward compatibility
promptWindowsSpeedUpResult: 'no',
} );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockDialogShowMessageBox ).toHaveBeenCalled();
} );
} );

describe( 'user response handling', () => {
it( 'should save "yes" response with current app version and dontAskAgain false', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 0, checkboxChecked: false } ); // First button (yes)

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: false } );

expect( mockUpdateAppdata ).toHaveBeenCalledWith( {
promptWindowsSpeedUpResult: {
response: 'yes',
appVersion: currentVersion,
dontAskAgain: false,
},
} );
} );

it( 'should save "no" response with current app version and dontAskAgain false', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } ); // Second button (no)

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: false } );

expect( mockUpdateAppdata ).toHaveBeenCalledWith( {
promptWindowsSpeedUpResult: {
response: 'no',
appVersion: currentVersion,
dontAskAgain: false,
},
} );
} );
} );

describe( 'dialog content', () => {
it( 'should show correct dialog title and message', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: false } );

expect( mockDialogShowMessageBox ).toHaveBeenCalledWith(
expect.any( BrowserWindow ),
expect.objectContaining( {
type: 'question',
title: expect.any( String ),
message: expect.stringContaining( 'Microsoft Defender' ),
buttons: expect.arrayContaining( [ expect.any( String ), expect.any( String ) ] ),
} )
);
} );

it( 'should show checkbox when skipIfAlreadyPrompted is true', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockDialogShowMessageBox ).toHaveBeenCalledWith(
expect.any( BrowserWindow ),
expect.objectContaining( {
checkboxLabel: expect.any( String ),
} )
);
} );

it( 'should not show checkbox when skipIfAlreadyPrompted is false', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: false } );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: false } );

expect( mockDialogShowMessageBox ).toHaveBeenCalledWith(
expect.any( BrowserWindow ),
expect.not.objectContaining( {
checkboxLabel: expect.anything(),
} )
);
} );
} );

describe( 'dontAskAgain functionality', () => {
it( 'should skip prompt when dontAskAgain is true regardless of version', async () => {
mockLoadUserData.mockResolvedValue( {
sites: [],
snapshots: [],
promptWindowsSpeedUpResult: {
response: 'no',
appVersion: '1.2.2', // Previous version
dontAskAgain: true,
},
} );

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockDialogShowMessageBox ).not.toHaveBeenCalled();
} );

it( 'should save dontAskAgain true when checkbox is checked with "yes" response', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 0, checkboxChecked: true } ); // First button (yes) with checkbox

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockUpdateAppdata ).toHaveBeenCalledWith( {
promptWindowsSpeedUpResult: {
response: 'yes',
appVersion: currentVersion,
dontAskAgain: true,
},
} );
} );

it( 'should save dontAskAgain true when checkbox is checked with "no" response', async () => {
mockLoadUserData.mockResolvedValue( { sites: [], snapshots: [] } );
mockDialogShowMessageBox.mockResolvedValue( { response: 1, checkboxChecked: true } ); // Second button (no) with checkbox

await promptWindowsSpeedUpSites( { skipIfAlreadyPrompted: true } );

expect( mockUpdateAppdata ).toHaveBeenCalledWith( {
promptWindowsSpeedUpResult: {
response: 'no',
appVersion: currentVersion,
dontAskAgain: true,
},
} );
} );
} );
} );
Loading