Skip to content
This repository has been archived by the owner on Jan 1, 2025. It is now read-only.

Commit

Permalink
refactor: e2e tests refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsSim committed Mar 16, 2024
1 parent 88ca09c commit 15aabe7
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 246 deletions.
158 changes: 44 additions & 114 deletions src/tests/e2e/installer.spec.js
Original file line number Diff line number Diff line change
@@ -1,196 +1,126 @@
const { _electron: electron } = require( 'playwright' );
const { test, expect } = require( '@playwright/test' );

Check warning on line 1 in src/tests/e2e/installer.spec.js

View workflow job for this annotation

GitHub Actions / build-launcher (macos-latest)

Slow Test

src/tests/e2e/installer.spec.js took 5.1m
const { findLatestBuild, parseElectronApp, stubDialog } = require( 'electron-playwright-helpers' );
const { stubDialog } = require( 'electron-playwright-helpers' );
const { promisify } = require( 'util' );

const path = require( 'path' );
const exec = promisify( require( 'child_process' ).exec );
const fs = require( 'fs-extra' );
const setupTest = require( './setup-test' );

test.describe( 'installer', () => {

// Timeout for long tests
const INSTALL_TIMEOUT_MS = 15 * 60 * 1000; // 15 minutes

/** @type {import('playwright').Page} */
let window;

/** @type {import('playwright').ElectronApplication} */
let electronApp;

/** @type {string} */
let latestBuild;

/** @type {import('electron-playwright-helpers').ElectronAppInfo} */
let appInfo;

/** @type {string} */
let exeDir;

/** @type {string} */
let appData;

/** @type {string} */
let installDir;

test.beforeAll( () => {
latestBuild = findLatestBuild( '../release' );
appInfo = parseElectronApp( latestBuild );
exeDir = path.dirname( appInfo.executable );
appData = process.platform == 'win32' ? exeDir :
require( 'os' ).homedir() + '/Library/Application Support/FreeSO Launcher';
installDir = process.platform == 'win32' ? 'C:\\Users\\Public\\TéstFõldér' :
appData + '/GameComponents';

fs.existsSync( `${appData}/FSOLauncher.ini` ) && fs.unlinkSync( `${appData}/FSOLauncher.ini` );
} );

test.beforeEach( async () => {
// Pass in --test-mode for headless testing
electronApp = await electron.launch( {
timeout: 60000,
cwd: exeDir,
args: [ appInfo.main, '--test-mode=true' ], // Main file from package.json
executablePath: appInfo.executable // Path to the Electron executable
} );
console.info( '[beforeEach] launched electronApp' );

// Log main process
electronApp.process().stdout.on( 'data', data => console.info( `[main] ${data}` ) );
electronApp.process().stderr.on( 'data', error => console.info( `[main] ${error}` ) );

window = await electronApp.firstWindow();
console.info( '[beforeEach] waited for firstWindow' );

// Log renderer process
window.on( 'console', log => console.info( `[renderer] ${log.text()}` ) );

await window.waitForLoadState( 'load' ); // Waits for the page to be completely loaded
console.info( '[beforeEach] achieved loadState' );
await window.locator( '[data-insprog="true"]' ).waitFor();
console.info( '[beforeEach] INS_PROG was received by renderer' );
} );

test.afterEach( async () => {
try {
console.info( '[afterEach] setting global.willQuit to true...' );
await electronApp.evaluate( async () => global.willQuit = true );
console.info( '[afterEach] global.willQuit has been set to true - attempting to close the app...' );
await electronApp.close();
console.info( '[afterEach] the app has been closed.' );
} catch ( err ) {
console.error( '[afterEach] an error occurred:', err );
}
} );
const T = setupTest( test );

test( 'performs a complete installation', async () => {
await window.locator( '[page-trigger="installer"]' ).click();
await window.locator( '#full-install-button' ).waitFor();
await window.locator( '#full-install-button' ).click();
await T.getWindow().locator( '[page-trigger="installer"]' ).click();
await T.getWindow().locator( '#full-install-button' ).waitFor();
await T.getWindow().locator( '#full-install-button' ).click();

if ( process.platform === 'win32' ) {
await stubDialog( electronApp, 'showOpenDialog', { filePaths: [ installDir ] } );
await window.locator( '.oneclick-install-select' ).click();
await window.locator( '.oneclick-install-confirm' ).click();
await stubDialog( T.getElectronApp(), 'showOpenDialog', { filePaths: [ T.getInstallDir() ] } );
await T.getWindow().locator( '.oneclick-install-select' ).click();
await T.getWindow().locator( '.oneclick-install-confirm' ).click();
} else {
await window.locator( '[data-response-id="FULL_INSTALL_CONFIRM"] .yes-button' ).click();
await T.getWindow().locator( '[data-response-id="FULL_INSTALL_CONFIRM"] .yes-button' ).click();
}

// Full installation started
expect( await window.locator( '#full-install' ).isVisible() ).toBeTruthy();
expect( await T.getWindow().locator( '#full-install' ).isVisible() ).toBeTruthy();

// Wait for the installation to finish
test.setTimeout( INSTALL_TIMEOUT_MS );
await window.locator( '#full-install' ).waitFor( { state: 'hidden', timeout: INSTALL_TIMEOUT_MS } );
await T.getWindow().locator( '#full-install' ).waitFor( { state: 'hidden', timeout: INSTALL_TIMEOUT_MS } );

// Expect no errors when the installation finishes
expect( await window.locator( '.modal-error' ).isVisible() ).toBeFalsy();
expect( await T.getWindow().locator( '.modal-error' ).isVisible() ).toBeFalsy();

// Go to the installer and make sure the checkmarks are there
await window.locator( '[page-trigger="installer"]' ).dblclick();
expect( await window.locator( '.item.installed[install="FSO"]' ).isVisible() ).toBeTruthy();
expect( await window.locator( '.item.installed[install="TSO"]' ).isVisible() ).toBeTruthy();
await T.getWindow().locator( '[page-trigger="installer"]' ).dblclick();
expect( await T.getWindow().locator( '.item.installed[install="FSO"]' ).isVisible() ).toBeTruthy();
expect( await T.getWindow().locator( '.item.installed[install="TSO"]' ).isVisible() ).toBeTruthy();

await window.locator( 'button.launch' ).click();
await T.getWindow().locator( 'button.launch' ).click();

// Expect no errors when launching the game
expect( await window.locator( '.modal-error' ).isVisible() ).toBeFalsy();
expect( await T.getWindow().locator( '.modal-error' ).isVisible() ).toBeFalsy();

await killGame();
} );

test( 'is still installed after a launcher restart', async () => {
await window.locator( '[page-trigger="installer"]' ).click();
expect( await window.locator( '.item.installed[install="FSO"]' ).isVisible() ).toBeTruthy();
expect( await window.locator( '.item.installed[install="TSO"]' ).isVisible() ).toBeTruthy();
await T.getWindow().locator( '[page-trigger="installer"]' ).click();
expect( await T.getWindow().locator( '.item.installed[install="FSO"]' ).isVisible() ).toBeTruthy();
expect( await T.getWindow().locator( '.item.installed[install="TSO"]' ).isVisible() ).toBeTruthy();
} );

test( 'installs Simitone', async () => {
await window.locator( '[page-trigger="simitone"]' ).click();
await window.locator( '#simitone-install-button' ).click();
await T.getWindow().locator( '[page-trigger="simitone"]' ).click();
await T.getWindow().locator( '#simitone-install-button' ).click();

expect( await window.locator( '.modal-error' ).isVisible() ).toBeFalsy();
expect( await T.getWindow().locator( '.modal-error' ).isVisible() ).toBeFalsy();

await window.locator( '[data-response-id="INSTALL_COMPONENT"] .yes-button' ).click();
await T.getWindow().locator( '[data-response-id="INSTALL_COMPONENT"] .yes-button' ).click();

if ( process.platform == 'win32' ) {
await stubDialog( electronApp, 'showOpenDialog', { filePaths: [ installDir ] } );
await stubDialog( T.getElectronApp(), 'showOpenDialog', { filePaths: [ T.getInstallDir() ] } );
}

const dlTitle = await window.locator( '#downloads-page .download .progress-title' ).textContent();
const dlId = await window.locator( '#downloads-page .download' ).getAttribute( 'id' );
const dlTitle = await T.getWindow().locator( '#downloads-page .download .progress-title' ).textContent();
const dlId = await T.getWindow().locator( '#downloads-page .download' ).getAttribute( 'id' );

expect( dlTitle.toLowerCase() ).toContain( 'simitone' );

console.info( 'test: Simitone installation started' );
test.setTimeout( INSTALL_TIMEOUT_MS );

// Wait for the installer to finish
await window.locator( `#${dlId}.stopped` ).waitFor( { timeout: INSTALL_TIMEOUT_MS } );
await T.getWindow().locator( `#${dlId}.stopped` ).waitFor( { timeout: INSTALL_TIMEOUT_MS } );

await window.locator( '[page-trigger="simitone"]' ).click();
await window.locator( '#simitone-play-button' ).waitFor();
await T.getWindow().locator( '[page-trigger="simitone"]' ).click();
await T.getWindow().locator( '#simitone-play-button' ).waitFor();
} );

test( 'installs Remesh Package', async () => {
await window.locator( '[page-trigger="installer"]' ).click();
await window.locator( '[install="RMS"]' ).click();
await T.getWindow().locator( '[page-trigger="installer"]' ).click();
await T.getWindow().locator( '[install="RMS"]' ).click();

expect( await window.locator( '.modal-error' ).isVisible() ).toBeFalsy();
expect( await T.getWindow().locator( '.modal-error' ).isVisible() ).toBeFalsy();

await window.locator( '[data-response-id="INSTALL_COMPONENT"] .yes-button' ).click();
await T.getWindow().locator( '[data-response-id="INSTALL_COMPONENT"] .yes-button' ).click();

const dlTitle = await window.locator( '#downloads-page .download .progress-title' ).textContent();
const dlId = await window.locator( '#downloads-page .download' ).getAttribute( 'id' );
const dlTitle = await T.getWindow().locator( '#downloads-page .download .progress-title' ).textContent();
const dlId = await T.getWindow().locator( '#downloads-page .download' ).getAttribute( 'id' );

expect( dlTitle.toLowerCase() ).toContain( 'remesh' );

console.info( 'test: Remesh package installation started for FreeSO' );
test.setTimeout( INSTALL_TIMEOUT_MS );

// Wait for the installer to finish
await window.locator( `#${dlId}.stopped` ).waitFor( { timeout: INSTALL_TIMEOUT_MS } );
await T.getWindow().locator( `#${dlId}.stopped` ).waitFor( { timeout: INSTALL_TIMEOUT_MS } );

const dirPath = process.platform == 'win32' ?
installDir + '/FreeSO Game/FreeSO/Content/MeshReplace' :
installDir + '/FreeSO/Content/MeshReplace';
T.getInstallDir() + '/FreeSO Game/FreeSO/Content/MeshReplace' :
T.getInstallDir() + '/FreeSO/Content/MeshReplace';

expect( await fs.pathExists( dirPath ) ).toBeTruthy();
expect( ( await fs.readdir( dirPath ) ).length ).toBeGreaterThan( 0 );

// Now for Simitone
const dlTitleSimitone = await window.locator( '#downloads-page .download:not(.stopped) .progress-title' ).textContent();
const dlIdSimitone = await window.locator( '#downloads-page .download:not(.stopped)' ).getAttribute( 'id' );
const dlTitleSimitone = await T.getWindow().locator( '#downloads-page .download:not(.stopped) .progress-title' ).textContent();
const dlIdSimitone = await T.getWindow().locator( '#downloads-page .download:not(.stopped)' ).getAttribute( 'id' );

expect( dlTitleSimitone.toLowerCase() ).toContain( 'remesh' );

console.info( 'test: Remesh package installation started for Simitone' );
test.setTimeout( INSTALL_TIMEOUT_MS );

// Wait for the installer to finish
await window.locator( `#${dlIdSimitone}.stopped` ).waitFor( { timeout: INSTALL_TIMEOUT_MS } );
await T.getWindow().locator( `#${dlIdSimitone}.stopped` ).waitFor( { timeout: INSTALL_TIMEOUT_MS } );

const dirPathSimitone = installDir + '/Simitone for Windows/Content/MeshReplace';
const dirPathSimitone = T.getInstallDir() + '/Simitone for Windows/Content/MeshReplace';

expect( await fs.pathExists( dirPathSimitone ) ).toBeTruthy();
expect( ( await fs.readdir( dirPathSimitone ) ).length ).toBeGreaterThan( 0 );
Expand Down
72 changes: 3 additions & 69 deletions src/tests/e2e/main.spec.js
Original file line number Diff line number Diff line change
@@ -1,81 +1,15 @@
const { _electron: electron } = require( 'playwright' );
const { test, expect } = require( '@playwright/test' );
const { findLatestBuild, parseElectronApp } = require( 'electron-playwright-helpers' );
const fs = require( 'fs-extra' );
const setupTest = require( './setup-test' );

test.describe( 'main', () => {
/** @type {import('playwright').Page} */
let window;

/** @type {import('playwright').ElectronApplication} */
let electronApp;

/** @type {string} */
let latestBuild;

/** @type {import('electron-playwright-helpers').ElectronAppInfo} */
let appInfo;

/** @type {string} */
let exeDir;

/** @type {string} */
let appData;

test.beforeAll( () => {
latestBuild = findLatestBuild( '../release' );
appInfo = parseElectronApp( latestBuild );
exeDir = require( 'path' ).dirname( appInfo.executable );
appData = process.platform == 'win32' ? exeDir :
require( 'os' ).homedir() + '/Library/Application Support/FreeSO Launcher';

// Delete config file if it exists before testing
fs.existsSync( `${appData}/FSOLauncher.ini` ) && fs.unlinkSync( `${appData}/FSOLauncher.ini` );
} );

test.beforeEach( async () => {
// Pass in --test-mode for headless testing
electronApp = await electron.launch( {
timeout: 60000,
cwd: exeDir,
args: [ appInfo.main, '--test-mode=true' ], // Main file from package.json
executablePath: appInfo.executable // Path to the Electron executable
} );
console.info( '[beforeEach] launched electronApp' );

// Log main process
electronApp.process().stdout.on( 'data', data => console.info( `[main] ${data}` ) );
electronApp.process().stderr.on( 'data', error => console.info( `[main] ${error}` ) );

window = await electronApp.firstWindow();
console.info( '[beforeEach] waited for firstWindow' );

// Log renderer process
window.on( 'console', log => console.info( `[renderer] ${log.text()}` ) );

await window.waitForLoadState( 'load' ); // Waits for the page to be completely loaded
console.info( '[beforeEach] achieved loadState' );
await window.locator( '[data-insprog="true"]' ).waitFor();
console.info( '[beforeEach] INS_PROG was received by renderer' );
} );

test.afterEach( async () => {
try {
console.info( '[afterEach] setting global.willQuit to true...' );
await electronApp.evaluate( async () => global.willQuit = true );
console.info( '[afterEach] global.willQuit has been set to true - attempting to close the app...' );
await electronApp.close();
console.info( '[afterEach] the app has been closed.' );
} catch ( err ) {
console.error( '[afterEach] an error occurred:', err );
}
} );
const T = setupTest( test );

test( 'starts the app', () => {
// Setup and teardown
} );

test( 'config file is present', async () => {
expect( await fs.exists( appData + '/FSOLauncher.ini' ) ).toBeTruthy();
expect( await fs.exists( T.getAppData() + '/FSOLauncher.ini' ) ).toBeTruthy();
} );
} );
Loading

0 comments on commit 15aabe7

Please sign in to comment.