mirror of
https://github.com/kiwix/kiwix-js.git
synced 2025-08-03 19:27:11 -04:00
Added an automated Selenium UI test for a small Zimit2 archive (#1286)
* Selenium ui test * Added android test * New test * Fixed all the tests * Fixed the failing tests * Update tonedear.e2e.spec.js * Reducing Time Wait * Adding tests in every files * Fixing tests again * Fixing tests again 2 * Increased Time Out for images verififcation * Fixing tests * Update tonedear.e2e.spec.js * Removing of Dialogue box which fails the tests & increasing tests on different browsers * Delete tests/e2e/spec/tonedear.js * Remove unwanted image files * Removing extra test made on new versions of browsers * removing reusing same driver in test file ff70 * Fixing the test fail issue * increasing the timeout and remove the tests from ff70 to test * fixing tests * fixing tests * Testing if bs works or not * trying again * Update edge18.bs.runner.js * Update firefox70.bs.runner.js * Update firefox70.bs.runner.js * Adding all the working code from Dummy PR * Removed Unnecessary codes from tonedear.e2e.spec.js * fixed service worker const issue * Added service worker api testing Signed-off-by: THEBOSS0369 <anujkumsharma9876@gmail.com> --------- Signed-off-by: THEBOSS0369 <anujkumsharma9876@gmail.com>
This commit is contained in:
parent
56b2a5c671
commit
47db0e7efd
@ -6,10 +6,12 @@ import path from 'path';
|
||||
|
||||
const rayCharlesBaseFile = path.resolve('./tests/zims/legacy-ray-charles/wikipedia_en_ray_charles_2015-06.zimaa');
|
||||
const gutenbergRoBaseFile = path.resolve('./tests/zims/gutenberg-ro/gutenberg_ro_all_2023-08.zim');
|
||||
const tonedearBaseFile = path.resolve('./tests/zims/tonedear/tonedear.com_en_2024-09.zim');
|
||||
const downloadDir = path.resolve('./tests/');
|
||||
|
||||
export default {
|
||||
rayCharlesBaseFile: rayCharlesBaseFile,
|
||||
gutenbergRoBaseFile: gutenbergRoBaseFile,
|
||||
tonedearBaseFile: tonedearBaseFile,
|
||||
downloadDir: downloadDir
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Builder } from 'selenium-webdriver';
|
||||
import { Options } from 'selenium-webdriver/chrome.js';
|
||||
import gutenbergRo from '../../spec/gutenberg_ro.e2e.spec.js';
|
||||
import tonedear from '../../spec/tonedear.e2e.spec.js'
|
||||
import paths from '../../paths.js';
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
@ -37,8 +38,9 @@ async function loadChromeDriver () {
|
||||
// Maximize the window so that full browser state is visible in the screenshots
|
||||
// await driver_chrome.manage().window().maximize(); // Not supported in this version / Selenium
|
||||
|
||||
console.log('\x1b[33m%s\x1b[0m', 'Running Gutenberg tests only for this browser version');
|
||||
console.log('\x1b[33m%s\x1b[0m', 'Running Gutenberg and Tonedear tests only for this browser version');
|
||||
console.log(' ');
|
||||
|
||||
// make sure to use await running tests or we are charged unnecessarily on Browserstack
|
||||
await gutenbergRo.runTests(await loadChromeDriver());
|
||||
await tonedear.runTests(await loadChromeDriver());
|
||||
|
@ -2,6 +2,7 @@ import { Builder } from 'selenium-webdriver';
|
||||
import { Options } from 'selenium-webdriver/chrome.js';
|
||||
import legacyRayCharles from '../../spec/legacy-ray_charles.e2e.spec.js';
|
||||
import gutenbergRo from '../../spec/gutenberg_ro.e2e.spec.js';
|
||||
import tonedearTests from '../../spec/tonedear.e2e.spec.js';
|
||||
import paths from '../../paths.js';
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
@ -20,10 +21,12 @@ async function loadChromiumDriver () {
|
||||
return driver;
|
||||
};
|
||||
|
||||
// Preserve the order of loading, because when a user runs these on local machine, the second driver will be on top of and cover the first one
|
||||
// so we need to use the second one first
|
||||
// Preserve the order of loading, because when a user runs these on local machine, the third driver will be on top of and cover the first one
|
||||
// so we need to use the third one first
|
||||
const driver_for_tonedear = await loadChromiumDriver();
|
||||
const driver_for_gutenberg = await loadChromiumDriver();
|
||||
const driver_for_ray_charles = await loadChromiumDriver();
|
||||
|
||||
await legacyRayCharles.runTests(driver_for_ray_charles);
|
||||
await gutenbergRo.runTests(driver_for_gutenberg);
|
||||
await tonedearTests.runTests(driver_for_tonedear);
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { Builder } from 'selenium-webdriver';
|
||||
import legacyRayCharles from '../../spec/legacy-ray_charles.e2e.spec.js';
|
||||
import gutenbergRo from '../../spec/gutenberg_ro.e2e.spec.js';
|
||||
import tonedear from '../../spec/tonedear.e2e.spec.js';
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
// Input capabilities
|
||||
const capabilities = {
|
||||
'browserstack.idleTimeout': 300,
|
||||
'bstack:options': {
|
||||
os: 'Windows',
|
||||
osVersion: '10',
|
||||
@ -35,8 +37,10 @@ async function loadEdgeLegacyDriver () {
|
||||
return driver;
|
||||
};
|
||||
|
||||
const driver_edge_legacy = await loadEdgeLegacyDriver();
|
||||
await legacyRayCharles.runTests(driver_edge_legacy);
|
||||
// For this runner, we must use a single driver for all tests to avoid the other drivers
|
||||
// timing out while earlier tests complete
|
||||
const singleDriver = await loadEdgeLegacyDriver();
|
||||
|
||||
const driver_edge_gutenberg = await loadEdgeLegacyDriver();
|
||||
await gutenbergRo.runTests(driver_edge_gutenberg);
|
||||
await legacyRayCharles.runTests(singleDriver, null, true);
|
||||
await gutenbergRo.runTests(singleDriver, null, true);
|
||||
await tonedear.runTests(singleDriver);
|
||||
|
@ -2,6 +2,7 @@ import { Builder } from 'selenium-webdriver';
|
||||
import { Options } from 'selenium-webdriver/ie.js';
|
||||
import legacyRayCharles from '../../spec/legacy-ray_charles.e2e.spec.js';
|
||||
import gutenbergRo from '../../spec/gutenberg_ro.e2e.spec.js';
|
||||
import tonedear from '../../spec/tonedear.e2e.spec.js';
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
@ -18,3 +19,4 @@ async function loadIEModeDriver () {
|
||||
|
||||
await legacyRayCharles.runTests(await loadIEModeDriver(), ['jquery']);
|
||||
await gutenbergRo.runTests(await loadIEModeDriver(), ['jquery']);
|
||||
await tonedear.runTests(await loadIEModeDriver(), ['jquery']);
|
||||
|
@ -2,6 +2,7 @@ import { Builder } from 'selenium-webdriver';
|
||||
import { Options } from 'selenium-webdriver/edge.js';
|
||||
import legacyRayCharles from '../../spec/legacy-ray_charles.e2e.spec.js';
|
||||
import gutenbergRo from '../../spec/gutenberg_ro.e2e.spec.js';
|
||||
import tonedearTests from '../../spec/tonedear.e2e.spec.js';
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
async function loadMSEdgeDriver () {
|
||||
@ -17,10 +18,12 @@ async function loadMSEdgeDriver () {
|
||||
return driver;
|
||||
};
|
||||
|
||||
// Preserve the order of loading, because when a user runs these on local machine, the second driver will be on top of and cover the first one
|
||||
// so we need to use the second one first
|
||||
// Preserve the order of loading, because when a user runs these on local machine, the third driver will be on top of and cover the first one
|
||||
// so we need to use the third one first
|
||||
const driver_for_tonedear = await loadMSEdgeDriver();
|
||||
const driver_for_gutenberg = await loadMSEdgeDriver();
|
||||
const driver_for_ray_charles = await loadMSEdgeDriver();
|
||||
|
||||
await legacyRayCharles.runTests(driver_for_ray_charles);
|
||||
await gutenbergRo.runTests(driver_for_gutenberg);
|
||||
await tonedearTests.runTests(driver_for_tonedear);
|
||||
|
@ -2,6 +2,7 @@ import { Builder } from 'selenium-webdriver';
|
||||
import firefox from 'selenium-webdriver/firefox.js';
|
||||
import legacyRayCharles from '../../spec/legacy-ray_charles.e2e.spec.js';
|
||||
import gutenbergRo from '../../spec/gutenberg_ro.e2e.spec.js';
|
||||
import tonedearTests from '../../spec/tonedear.e2e.spec.js';
|
||||
import paths from '../../paths.js';
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
@ -23,10 +24,12 @@ async function loadFirefoxDriver () {
|
||||
return driver;
|
||||
};
|
||||
|
||||
// Preserve the order of loading, because when a user runs these on local machine, the second driver will be on top of and cover the first one
|
||||
// so we need to use the second one first
|
||||
// Preserve the order of loading, because when a user runs these on local machine, the third driver will be on top of and cover the first one
|
||||
// so we need to use the third one first
|
||||
const driver_for_tonedear = await loadFirefoxDriver();
|
||||
const driver_for_gutenberg = await loadFirefoxDriver();
|
||||
const driver_for_ray_charles = await loadFirefoxDriver();
|
||||
|
||||
await legacyRayCharles.runTests(driver_for_ray_charles);
|
||||
await gutenbergRo.runTests(driver_for_gutenberg);
|
||||
await tonedearTests.runTests(driver_for_tonedear);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Builder } from 'selenium-webdriver';
|
||||
import gutenbergRo from '../../spec/gutenberg_ro.e2e.spec.js';
|
||||
import tonedear from '../../spec/tonedear.e2e.spec.js';
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
// Input capabilities
|
||||
@ -31,9 +32,13 @@ async function loadFirefoxDriver () {
|
||||
};
|
||||
|
||||
const driver_gutenberg_fx = await loadFirefoxDriver();
|
||||
const driver_tonedear_fx = await loadFirefoxDriver();
|
||||
|
||||
// Run test in SW mode only
|
||||
console.log('\x1b[33m%s\x1b[0m', 'Running Gutenberg tests in ServiceWorker mode only for this browser version');
|
||||
console.log('\x1b[33m%s\x1b[0m', 'Running Gutenberg tests in ServiceWorker mode and Tonedear tests in JQuery only for this browser version');
|
||||
console.log(' ');
|
||||
|
||||
await gutenbergRo.runTests(driver_gutenberg_fx, ['serviceworker']);
|
||||
await gutenbergRo.runTests(driver_gutenberg_fx);
|
||||
// Skipping Tonedear tests in SW mode for Firefox 70 due to unsupported navigation issues
|
||||
// Reason-> Because the browsers below Firefox 77 does not support the replaceAll method, which is used in the Zimit
|
||||
await tonedear.runTests(driver_tonedear_fx, ['jquery']);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Builder } from 'selenium-webdriver';
|
||||
import legacyRayCharles from '../../spec/legacy-ray_charles.e2e.spec.js';
|
||||
import gutenbergRo from '../../spec/gutenberg_ro.e2e.spec.js';
|
||||
import tonedearTests from '../../spec/tonedear.e2e.spec.js';
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
@ -42,3 +43,6 @@ await legacyRayCharles.runTests(driver_legacy_safari, ['jquery']);
|
||||
|
||||
const driver_gutenberg_safari = await loadSafariDriver();
|
||||
await gutenbergRo.runTests(driver_gutenberg_safari, ['jquery']);
|
||||
|
||||
const driver_tonedear_safari = await loadSafariDriver();
|
||||
await tonedearTests.runTests(driver_tonedear_safari, ['jquery']);
|
||||
|
@ -41,9 +41,10 @@ const gutenbergRoBaseFile = BROWSERSTACK ? '/tests/zims/gutenberg-ro/gutenberg_r
|
||||
* Run the tests
|
||||
* @param {WebDriver} driver Selenium WebDriver object
|
||||
* @param {Array} modes Array of modes to run the tests in
|
||||
* @param {boolean} keepDriver Whether to keep the driver open after the tests have run
|
||||
* @returns {Promise<void>} A Promise for the completion of the tests
|
||||
*/
|
||||
function runTests (driver, modes) {
|
||||
function runTests (driver, modes, keepDriver) {
|
||||
let browserName, browserVersion;
|
||||
driver.getCapabilities().then(function (caps) {
|
||||
browserName = caps.get('browserName');
|
||||
@ -180,7 +181,7 @@ function runTests (driver, modes) {
|
||||
} else {
|
||||
// Skip remaining SW mode tests if the browser does not support the SW API
|
||||
console.log('\x1b[33m%s\x1b[0m', ' Skipping SW mode tests because browser does not support API');
|
||||
await driver.quit();
|
||||
if (!keepDriver) await driver.quit();
|
||||
}
|
||||
// Disable source verification in SW mode as the dialogue box gave incosistent test results in automated tests
|
||||
if (mode === 'serviceworker') {
|
||||
@ -397,8 +398,8 @@ function runTests (driver, modes) {
|
||||
assert.ok(downloadFileStatus);
|
||||
|
||||
// exit if every test and mode is completed
|
||||
if (mode === modes[modes.length - 1]) {
|
||||
return driver.quit();
|
||||
if (mode === modes[modes.length - 1] && !keepDriver) {
|
||||
await driver.quit();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -58,9 +58,10 @@ console.log('\nLoading archive:\n' + rayCharlesAllParts + '\n');
|
||||
* Run the tests
|
||||
* @param {WebDriver} driver Selenium WebDriver object
|
||||
* @param {array} modes Array of modes to run the tests in
|
||||
* @param {boolean} keepDriver Whether to keep the driver open after the tests have run
|
||||
* @returns {Promise<void>} A Promise for the completion of the tests
|
||||
*/
|
||||
function runTests (driver, modes) {
|
||||
function runTests (driver, modes, keepDriver) {
|
||||
let browserName, browserVersion;
|
||||
driver.getCapabilities().then(function (caps) {
|
||||
browserName = caps.get('browserName');
|
||||
@ -192,7 +193,7 @@ function runTests (driver, modes) {
|
||||
} else {
|
||||
// Skip remaining SW mode tests if the browser does not support the SW API
|
||||
console.log('\x1b[33m%s\x1b[0m', ' Skipping SW mode tests because browser does not support API');
|
||||
await driver.quit();
|
||||
if (!keepDriver) await driver.quit();
|
||||
}
|
||||
// Disable source verification in SW mode as the dialogue box gave incosistent test results in automated tests
|
||||
if (mode === 'serviceworker') {
|
||||
@ -345,7 +346,7 @@ function runTests (driver, modes) {
|
||||
const title = await driver.findElement(By.id('titleHeading')).getText();
|
||||
assert.equal('Ray Charles', title);
|
||||
// If we have reached the last mode, quit the driver
|
||||
if (mode === modes[modes.length - 1]) {
|
||||
if (mode === modes[modes.length - 1] && !keepDriver) {
|
||||
await driver.quit();
|
||||
}
|
||||
});
|
||||
|
248
tests/e2e/spec/tonedear.e2e.spec.js
Normal file
248
tests/e2e/spec/tonedear.e2e.spec.js
Normal file
@ -0,0 +1,248 @@
|
||||
/* eslint-disable no-undef */
|
||||
import { By, until } from 'selenium-webdriver';
|
||||
import assert from 'assert';
|
||||
import paths from '../paths.js';
|
||||
|
||||
const BROWSERSTACK = !!process.env.BROWSERSTACK_LOCAL_IDENTIFIER;
|
||||
const port = BROWSERSTACK ? '8099' : '8080';
|
||||
const tonedearBaseFile = BROWSERSTACK ? '/tests/zims/tonedear/tonedear.com_en_2024-09.zim' : paths.tonedearBaseFile;
|
||||
|
||||
/**
|
||||
* Run the tests
|
||||
* @param {WebDriver} driver Selenium WebDriver object
|
||||
* @param {Array} modes Array of modes to run the tests in
|
||||
* @param {boolean} keepDriver Whether to keep the driver open after the tests have run
|
||||
* @returns {Promise<void>} A Promise for the completion of the tests
|
||||
*/
|
||||
function runTests (driver, modes, keepDriver) {
|
||||
let browserName, browserVersion;
|
||||
driver.getCapabilities().then(function (caps) {
|
||||
browserName = caps.get('browserName');
|
||||
browserVersion = caps.get('browserVersion');
|
||||
console.log('\nRunning Tonedear tests on: ' + browserName + ' ' + browserVersion);
|
||||
});
|
||||
|
||||
// Set the implicit wait to 3 seconds
|
||||
driver.manage().setTimeouts({ implicit: 3000 });
|
||||
|
||||
// Run in both jquery and serviceworker modes by default
|
||||
if (!modes) {
|
||||
modes = ['jquery', 'serviceworker'];
|
||||
}
|
||||
|
||||
modes.forEach(function (mode) {
|
||||
let serviceWorkerAPI = true;
|
||||
describe('Tonedear test ' + (mode === 'jquery' ? '[JQuery mode]' : '[SW mode]'), function () {
|
||||
this.timeout(60000);
|
||||
this.slow(10000);
|
||||
|
||||
it('Load Kiwix JS and check title', async function () {
|
||||
await driver.get('http://localhost:' + port + '/dist/www/index.html?noPrompts=true');
|
||||
await driver.sleep(1300);
|
||||
await driver.navigate().refresh();
|
||||
await driver.sleep(800);
|
||||
const title = await driver.getTitle();
|
||||
assert.equal('Kiwix', title);
|
||||
});
|
||||
|
||||
it('Switch to ' + mode + ' mode', async function () {
|
||||
const modeSelector = await driver.wait(until.elementLocated(By.id(mode + 'ModeRadio')));
|
||||
await driver.wait(async function () {
|
||||
const elementIsVisible = await driver.executeScript(
|
||||
'var el=arguments[0]; el.scrollIntoView(true); setTimeout(function () {el.click();}, 50); return el.offsetParent;',
|
||||
modeSelector
|
||||
);
|
||||
return elementIsVisible;
|
||||
}, 5000);
|
||||
await driver.sleep(1300);
|
||||
|
||||
// Check for and click any approve button in dialogue box
|
||||
try {
|
||||
const activeAlertModal = await driver.findElement(By.css('.modal[style*="display: block"]'));
|
||||
if (activeAlertModal) {
|
||||
// Check if ServiceWorker mode API is supported
|
||||
serviceWorkerAPI = await driver.findElement(By.id('modalLabel')).getText().then(function (alertText) {
|
||||
return !/ServiceWorker\sAPI\snot\savailable/i.test(alertText);
|
||||
});
|
||||
}
|
||||
const approveButton = await driver.wait(until.elementLocated(By.id('approveConfirm')));
|
||||
await approveButton.click();
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (mode === 'jquery' || serviceWorkerAPI) {
|
||||
// Wait until the mode has switched
|
||||
await driver.sleep(2000);
|
||||
let serviceWorkerStatus = await driver.findElement(By.id('serviceWorkerStatus')).getText();
|
||||
try {
|
||||
if (mode === 'serviceworker') {
|
||||
assert.ok(true, /and\sregistered/i.test(serviceWorkerStatus));
|
||||
} else {
|
||||
assert.ok(true, /not\sregistered|unavailable/i.test(serviceWorkerStatus));
|
||||
}
|
||||
} catch (e) {
|
||||
if (!~modes.indexOf('serviceworker')) {
|
||||
// We can't switch to serviceworker mode if it is not being tested, so we should fail the test
|
||||
throw e;
|
||||
}
|
||||
// We failed to switch modes, so let's try switching back and switching to this mode again
|
||||
console.log('\x1b[33m%s\x1b[0m', ' Failed to switch to ' + mode + ' mode, trying again...');
|
||||
let otherModeSelector;
|
||||
await driver.wait(async function () {
|
||||
otherModeSelector = await driver.findElement(By.id(mode === 'jquery' ? 'serviceworkerModeRadio' : 'jqueryModeRadio'));
|
||||
}, 5000);
|
||||
// Click the other mode selector
|
||||
await otherModeSelector.click();
|
||||
// Wait until the mode has switched
|
||||
await driver.sleep(330);
|
||||
// Click the mode selector again
|
||||
await modeSelector.click();
|
||||
// Wait until the mode has switched
|
||||
await driver.sleep(330);
|
||||
serviceWorkerStatus = await driver.findElement(By.id('serviceWorkerStatus')).getText();
|
||||
if (mode === 'serviceworker') {
|
||||
assert.equal(true, /and\sregistered/i.test(serviceWorkerStatus));
|
||||
} else {
|
||||
assert.equal(true, /not\sregistered|unavailable/i.test(serviceWorkerStatus));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Skip remaining SW mode tests if the browser does not support the SW API
|
||||
console.log('\x1b[33m%s\x1b[0m', ' Skipping SW mode tests because browser does not support API');
|
||||
if (!keepDriver) await driver.quit();
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable source verification in SW mode as the dialogue box gave incosistent test results in automated tests
|
||||
if (mode === 'serviceworker') {
|
||||
const sourceVerificationCheckbox = await driver.findElement(By.id('enableSourceVerification'));
|
||||
if (await sourceVerificationCheckbox.isSelected()) {
|
||||
await sourceVerificationCheckbox.click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('Load Tonedear archive', async function () {
|
||||
if (!serviceWorkerAPI && mode === 'serviceworker') {
|
||||
console.log('\x1b[33m%s\x1b[0m', ' - Following test skipped:');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BROWSERSTACK) {
|
||||
const archiveFiles = await driver.findElement(By.id('archiveFiles'));
|
||||
await archiveFiles.sendKeys(tonedearBaseFile);
|
||||
await driver.executeScript('window.setLocalArchiveFromFileSelect();');
|
||||
const filesLength = await driver.executeScript('return document.getElementById("archiveFiles").files.length');
|
||||
assert.equal(1, filesLength);
|
||||
} else {
|
||||
await driver.executeScript('var files = arguments[0]; window.setRemoteArchives.apply(this, files);', [tonedearBaseFile]);
|
||||
await driver.sleep(1300);
|
||||
}
|
||||
});
|
||||
|
||||
it('Navigate to Android & iOS section', async function () {
|
||||
if (!serviceWorkerAPI && mode === 'serviceworker') {
|
||||
console.log('\x1b[33m%s\x1b[0m', ' - Following test skipped:');
|
||||
return;
|
||||
}
|
||||
|
||||
await driver.sleep(2000); // Give time for content to load
|
||||
await driver.switchTo().frame('articleContent');
|
||||
const androidIosLink = await driver.wait(until.elementLocated(By.css('a[href="android-ios-ear-training-app"]')), 5000);
|
||||
await androidIosLink.click();
|
||||
// Switch back to default content before handling dialogs or verifying content
|
||||
await driver.switchTo().defaultContent();
|
||||
// Wait time
|
||||
await driver.sleep(1000);
|
||||
});
|
||||
|
||||
it('Verify Android and iOS store images in ' + (mode === 'jquery' ? 'Restricted' : 'ServiceWorker') + ' mode', async function () {
|
||||
if (!serviceWorkerAPI && mode === 'jquery') {
|
||||
// Restricted mode test for data URIs
|
||||
const androidImage = await driver.findElement(By.css('img[alt="Get it on Google Play"]'));
|
||||
const iosImage = await driver.findElement(By.css('img[alt="Get the iOS app"]'));
|
||||
|
||||
// Verify src attribute has changed to a data URI
|
||||
const androidSrc = await androidImage.getAttribute('src');
|
||||
const iosSrc = await iosImage.getAttribute('src');
|
||||
|
||||
assert.ok(androidSrc.startsWith('data:image/png;base64,'), 'Android image src is a data URI');
|
||||
assert.ok(iosSrc.startsWith('data:image/png;base64,'), 'iOS image src is a data URI');
|
||||
|
||||
// Compare the first 30 characters of data URIs
|
||||
const androidDataSnippet = androidSrc.substring(22, 52);
|
||||
const iosDataSnippet = iosSrc.substring(22, 52);
|
||||
|
||||
// Expected snippet for comparison
|
||||
const expectedAndroidSnippet = 'iVBORw0KGgoAAAANSUhEUg';
|
||||
const expectedIosSnippet = 'iVBORw0KGgoAAAANSUhEUg';
|
||||
|
||||
assert.strictEqual(androidDataSnippet, expectedAndroidSnippet, 'Android image data matches expected');
|
||||
assert.strictEqual(iosDataSnippet, expectedIosSnippet, 'iOS image data matches expected');
|
||||
} else if (serviceWorkerAPI && mode === 'serviceworker') {
|
||||
try {
|
||||
// ServiceWorker mode test for image loading
|
||||
await driver.sleep(3000);
|
||||
|
||||
const swRegistration = await driver.executeScript('return navigator.serviceWorker.ready');
|
||||
assert.ok(swRegistration, 'Service Worker is registered');
|
||||
|
||||
// console.log('Current URL:', await driver.getCurrentUrl());
|
||||
|
||||
// Switch to the iframe that contains the Android and iOS images
|
||||
const iframe = await driver.findElement(By.id('articleContent'));
|
||||
await driver.switchTo().frame(iframe);
|
||||
|
||||
// Wait for images to be visible on the page inside the iframe
|
||||
await driver.wait(async function () {
|
||||
const images = await driver.findElements(By.css('img[alt="Get it on Google Play"], img[alt="Get the iOS app"]'));
|
||||
if (images.length === 0) return false;
|
||||
|
||||
// Check if all images are visible
|
||||
const visibility = await Promise.all(images.map(async (img) => {
|
||||
return await img.isDisplayed();
|
||||
}));
|
||||
return visibility.every((isVisible) => isVisible);
|
||||
}, 10000, 'No visible store images found after 10 seconds');
|
||||
|
||||
const androidImage = await driver.findElement(By.css('img[alt="Get it on Google Play"]'));
|
||||
const iosImage = await driver.findElement(By.css('img[alt="Get the iOS app"]'));
|
||||
|
||||
// Wait for images to load and verify dimensions
|
||||
await driver.wait(async function () {
|
||||
const androidLoaded = await driver.executeScript('return arguments[0].complete && arguments[0].naturalWidth > 0 && arguments[0].naturalHeight > 0;', androidImage);
|
||||
const iosLoaded = await driver.executeScript('return arguments[0].complete && arguments[0].naturalWidth > 0 && arguments[0].naturalHeight > 0;', iosImage);
|
||||
return androidLoaded && iosLoaded;
|
||||
}, 5000, 'Images did not load successfully');
|
||||
|
||||
const androidWidth = await driver.executeScript('return arguments[0].naturalWidth;', androidImage);
|
||||
const androidHeight = await driver.executeScript('return arguments[0].naturalHeight;', androidImage);
|
||||
|
||||
const iosWidth = await driver.executeScript('return arguments[0].naturalWidth;', iosImage);
|
||||
const iosHeight = await driver.executeScript('return arguments[0].naturalHeight;', iosImage);
|
||||
|
||||
assert.ok(androidWidth > 0 && androidHeight > 0, 'Android image has valid dimensions');
|
||||
assert.ok(iosWidth > 0 && iosHeight > 0, 'iOS image has valid dimensions');
|
||||
|
||||
// Switch back to the main content after finishing the checks
|
||||
await driver.switchTo().defaultContent();
|
||||
} catch (err) {
|
||||
// If we still can't find the images, log the page source to help debug
|
||||
console.error('Failed to find store images:', err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// exit if every test and mode is completed
|
||||
if (mode === modes[modes.length - 1] && !keepDriver) {
|
||||
await driver.quit();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
runTests: runTests
|
||||
};
|
BIN
tests/zims/tonedear/tonedear.com_en_2024-09.zim
Normal file
BIN
tests/zims/tonedear/tonedear.com_en_2024-09.zim
Normal file
Binary file not shown.
@ -1864,6 +1864,8 @@ async function archiveReadyCallback (archive) {
|
||||
if (settingsStore.getItem('trustedZimFiles') === null) {
|
||||
settingsStore.setItem('trustedZimFiles', '', Infinity);
|
||||
}
|
||||
// This is used for testing: if the noPrompts flag is set, we skip the source verification
|
||||
if (params.noPrompts) params.sourceVerification = false;
|
||||
if (params.sourceVerification && (params.contentInjectionMode === 'serviceworker' || params.contentInjectionMode === 'serviceworkerlocal')) {
|
||||
// Check if source of the zim file can be trusted.
|
||||
if (!(settingsStore.getItem('trustedZimFiles').includes(archive.file.name))) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user