More integration steps, fix bug related to only NM install
All checks were successful
Build and test project / build-and-test (push) Successful in 1m28s
All checks were successful
Build and test project / build-and-test (push) Successful in 1m28s
This commit is contained in:
@@ -903,9 +903,9 @@ test.describe('Custom patches', () => {
|
|||||||
await expect(page.locator('#error-message')).toContainText('Build failed');
|
await expect(page.locator('#error-message')).toContainText('Build failed');
|
||||||
await expect(page.locator('#btn-error-back')).toBeVisible();
|
await expect(page.locator('#btn-error-back')).toBeVisible();
|
||||||
|
|
||||||
// Go Back should return to patches step
|
// "Select different patches" should return to mode selection (auto mode)
|
||||||
await page.click('#btn-error-back');
|
await page.click('#btn-error-back');
|
||||||
await expect(page.locator('#step-patches')).not.toBeHidden();
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('with device — real patch failure with Go Back (Allow rotation)', async ({ page }) => {
|
test('with device — real patch failure with Go Back (Allow rotation)', async ({ page }) => {
|
||||||
@@ -936,11 +936,11 @@ test.describe('Custom patches', () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (doneOrError === 'error') {
|
if (doneOrError === 'error') {
|
||||||
// Build failed — verify Go Back works
|
// Build failed — "Select different patches" should return to mode selection
|
||||||
await expect(page.locator('#error-message')).toContainText('Build failed');
|
await expect(page.locator('#error-message')).toContainText('Build failed');
|
||||||
await expect(page.locator('#btn-error-back')).toBeVisible();
|
await expect(page.locator('#btn-error-back')).toBeVisible();
|
||||||
await page.click('#btn-error-back');
|
await page.click('#btn-error-back');
|
||||||
await expect(page.locator('#step-patches')).not.toBeHidden();
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
} else {
|
} else {
|
||||||
// Build succeeded — check if the patch was skipped
|
// Build succeeded — check if the patch was skipped
|
||||||
const logText = await page.locator('#build-log').textContent();
|
const logText = await page.locator('#build-log').textContent();
|
||||||
@@ -949,4 +949,105 @@ test.describe('Custom patches', () => {
|
|||||||
expect(hasSkip, 'Expected "Allow rotation" to be skipped or fail').toBe(true);
|
expect(hasSkip, 'Expected "Allow rotation" to be skipped or fail').toBe(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('with device — back navigation through auto mode flow', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await injectMockDevice(page);
|
||||||
|
await page.click('#btn-connect');
|
||||||
|
|
||||||
|
// Step 1: Device
|
||||||
|
await expect(page.locator('#step-device')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Device → Mode
|
||||||
|
await page.click('#btn-device-next');
|
||||||
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Mode → Patches
|
||||||
|
await page.click('input[name="mode"][value="patches"]');
|
||||||
|
await page.click('#btn-mode-next');
|
||||||
|
await expect(page.locator('#step-patches')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Patches → Back → Mode
|
||||||
|
await page.click('#btn-patches-back');
|
||||||
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Mode → NickelMenu config
|
||||||
|
await page.click('input[name="mode"][value="nickelmenu"]');
|
||||||
|
await page.click('#btn-mode-next');
|
||||||
|
await expect(page.locator('#step-nickelmenu')).not.toBeHidden();
|
||||||
|
|
||||||
|
// NM config → Back → Mode
|
||||||
|
await page.click('#btn-nm-back');
|
||||||
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Mode → NM config → Continue → NM review
|
||||||
|
await page.click('input[name="mode"][value="nickelmenu"]');
|
||||||
|
await page.click('#btn-mode-next');
|
||||||
|
await expect(page.locator('#step-nickelmenu')).not.toBeHidden();
|
||||||
|
await page.click('input[value="nickelmenu-only"]');
|
||||||
|
await page.click('#btn-nm-next');
|
||||||
|
await expect(page.locator('#step-nm-review')).not.toBeHidden();
|
||||||
|
|
||||||
|
// NM review → Back → NM config
|
||||||
|
await page.click('#btn-nm-review-back');
|
||||||
|
await expect(page.locator('#step-nickelmenu')).not.toBeHidden();
|
||||||
|
|
||||||
|
// NM config → Back → Mode
|
||||||
|
await page.click('#btn-nm-back');
|
||||||
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Mode → Back → Device
|
||||||
|
await page.click('#btn-mode-back');
|
||||||
|
await expect(page.locator('#step-device')).not.toBeHidden();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('no device — back navigation through manual mode flow', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await goToManualMode(page);
|
||||||
|
|
||||||
|
// Step 1: Mode
|
||||||
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Mode → Patches → Version selection
|
||||||
|
await page.click('input[name="mode"][value="patches"]');
|
||||||
|
await page.click('#btn-mode-next');
|
||||||
|
await expect(page.locator('#step-manual-version')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Version → Back → Mode
|
||||||
|
await page.click('#btn-manual-version-back');
|
||||||
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Mode → NickelMenu config
|
||||||
|
await page.click('input[name="mode"][value="nickelmenu"]');
|
||||||
|
await page.click('#btn-mode-next');
|
||||||
|
await expect(page.locator('#step-nickelmenu')).not.toBeHidden();
|
||||||
|
|
||||||
|
// NM config → Back → Mode
|
||||||
|
await page.click('#btn-nm-back');
|
||||||
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Mode → Patches → Version selection
|
||||||
|
await page.click('input[name="mode"][value="patches"]');
|
||||||
|
await page.click('#btn-mode-next');
|
||||||
|
await expect(page.locator('#step-manual-version')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Select version and model, confirm
|
||||||
|
await page.selectOption('#manual-version', '4.45.23646');
|
||||||
|
await page.locator('#manual-model').waitFor({ state: 'visible' });
|
||||||
|
await page.selectOption('#manual-model', 'N428');
|
||||||
|
await page.click('#btn-manual-confirm');
|
||||||
|
await expect(page.locator('#step-patches')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Patches → Back → Version
|
||||||
|
await page.click('#btn-patches-back');
|
||||||
|
await expect(page.locator('#step-manual-version')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Version → Back → Mode
|
||||||
|
await page.click('#btn-manual-version-back');
|
||||||
|
await expect(page.locator('#step-mode')).not.toBeHidden();
|
||||||
|
|
||||||
|
// Mode → Back → Connect
|
||||||
|
await page.click('#btn-mode-back');
|
||||||
|
await expect(page.locator('#step-connect')).not.toBeHidden();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -584,7 +584,7 @@ import JSZip from 'jszip';
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (nickelMenuOption === 'remove') {
|
if (nickelMenuOption === 'remove') {
|
||||||
await nmInstaller.loadAssets((msg) => { nmProgress.textContent = msg; });
|
await nmInstaller.loadAssets((msg) => { nmProgress.textContent = msg; }, false);
|
||||||
nmProgress.textContent = 'Writing KoboRoot.tgz...';
|
nmProgress.textContent = 'Writing KoboRoot.tgz...';
|
||||||
const tgz = await nmInstaller.getKoboRootTgz();
|
const tgz = await nmInstaller.getKoboRootTgz();
|
||||||
await device.writeFile(['.kobo', 'KoboRoot.tgz'], tgz);
|
await device.writeFile(['.kobo', 'KoboRoot.tgz'], tgz);
|
||||||
|
|||||||
@@ -25,19 +25,23 @@ class NickelMenuInstaller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Download and cache the bundled assets.
|
* Download and cache the bundled assets.
|
||||||
|
* @param {function} progressFn
|
||||||
|
* @param {boolean} [needConfig=true] - Whether to also load kobo-config.zip
|
||||||
*/
|
*/
|
||||||
async loadAssets(progressFn) {
|
async loadAssets(progressFn, needConfig = true) {
|
||||||
if (this.nickelMenuZip && this.koboConfigZip) return;
|
if (!this.nickelMenuZip) {
|
||||||
|
progressFn('Downloading NickelMenu...');
|
||||||
|
const nmResp = await fetch('nickelmenu/NickelMenu.zip');
|
||||||
|
if (!nmResp.ok) throw new Error('Failed to download NickelMenu.zip: HTTP ' + nmResp.status);
|
||||||
|
this.nickelMenuZip = await JSZip.loadAsync(await nmResp.arrayBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
progressFn('Downloading NickelMenu...');
|
if (needConfig && !this.koboConfigZip) {
|
||||||
const nmResp = await fetch('nickelmenu/NickelMenu.zip');
|
progressFn('Downloading configuration files...');
|
||||||
if (!nmResp.ok) throw new Error('Failed to download NickelMenu.zip: HTTP ' + nmResp.status);
|
const cfgResp = await fetch('nickelmenu/kobo-config.zip');
|
||||||
this.nickelMenuZip = await JSZip.loadAsync(await nmResp.arrayBuffer());
|
if (!cfgResp.ok) throw new Error('Failed to download kobo-config.zip: HTTP ' + cfgResp.status);
|
||||||
|
this.koboConfigZip = await JSZip.loadAsync(await cfgResp.arrayBuffer());
|
||||||
progressFn('Downloading configuration files...');
|
}
|
||||||
const cfgResp = await fetch('nickelmenu/kobo-config.zip');
|
|
||||||
if (!cfgResp.ok) throw new Error('Failed to download kobo-config.zip: HTTP ' + cfgResp.status);
|
|
||||||
this.koboConfigZip = await JSZip.loadAsync(await cfgResp.arrayBuffer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,7 +115,8 @@ class NickelMenuInstaller {
|
|||||||
* @param {function} progressFn
|
* @param {function} progressFn
|
||||||
*/
|
*/
|
||||||
async installToDevice(device, option, cfg, progressFn) {
|
async installToDevice(device, option, cfg, progressFn) {
|
||||||
await this.loadAssets(progressFn);
|
const needConfig = option !== 'nickelmenu-only';
|
||||||
|
await this.loadAssets(progressFn, needConfig);
|
||||||
|
|
||||||
// Always install KoboRoot.tgz
|
// Always install KoboRoot.tgz
|
||||||
progressFn('Writing KoboRoot.tgz...');
|
progressFn('Writing KoboRoot.tgz...');
|
||||||
@@ -172,7 +177,8 @@ class NickelMenuInstaller {
|
|||||||
* @returns {Uint8Array} zip contents
|
* @returns {Uint8Array} zip contents
|
||||||
*/
|
*/
|
||||||
async buildDownloadZip(option, cfg, progressFn) {
|
async buildDownloadZip(option, cfg, progressFn) {
|
||||||
await this.loadAssets(progressFn);
|
const needConfig = option !== 'nickelmenu-only';
|
||||||
|
await this.loadAssets(progressFn, needConfig);
|
||||||
|
|
||||||
progressFn('Building download package...');
|
progressFn('Building download package...');
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
|
|||||||
Reference in New Issue
Block a user