Add removal options
All checks were successful
Build and test project / build-and-test (push) Successful in 1m32s
All checks were successful
Build and test project / build-and-test (push) Successful in 1m32s
This commit is contained in:
@@ -10,7 +10,7 @@ const { expect } = require('@playwright/test');
|
||||
async function injectMockDevice(page, opts = {}) {
|
||||
const firmware = opts.firmware || '4.45.23646';
|
||||
const serial = opts.serial || 'N4280A0000000';
|
||||
await page.evaluate(({ hasNickelMenu, firmware, serial }) => {
|
||||
await page.evaluate(({ hasNickelMenu, hasKoreader, hasReaderlyFonts, hasScreensaver, firmware, serial }) => {
|
||||
const filesystem = {
|
||||
'.kobo': {
|
||||
_type: 'dir',
|
||||
@@ -38,6 +38,31 @@ async function injectMockDevice(page, opts = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
if (hasKoreader) {
|
||||
if (!filesystem['.adds']) filesystem['.adds'] = { _type: 'dir' };
|
||||
filesystem['.adds']['koreader'] = {
|
||||
_type: 'dir',
|
||||
'koreader.sh': { _type: 'file', content: '#!/bin/sh' },
|
||||
};
|
||||
}
|
||||
|
||||
if (hasReaderlyFonts) {
|
||||
filesystem['fonts'] = {
|
||||
_type: 'dir',
|
||||
'KF_Readerly-Regular.ttf': { _type: 'file', content: '' },
|
||||
'KF_Readerly-Italic.ttf': { _type: 'file', content: '' },
|
||||
'KF_Readerly-Bold.ttf': { _type: 'file', content: '' },
|
||||
'KF_Readerly-BoldItalic.ttf': { _type: 'file', content: '' },
|
||||
};
|
||||
}
|
||||
|
||||
if (hasScreensaver) {
|
||||
if (!filesystem['.kobo']['screensaver']) {
|
||||
filesystem['.kobo']['screensaver'] = { _type: 'dir' };
|
||||
}
|
||||
filesystem['.kobo']['screensaver']['moon.png'] = { _type: 'file', content: '' };
|
||||
}
|
||||
|
||||
window.__mockFS = filesystem;
|
||||
window.__mockWrittenFiles = {};
|
||||
|
||||
@@ -93,12 +118,26 @@ async function injectMockDevice(page, opts = {}) {
|
||||
}
|
||||
throw new DOMException('Not found: ' + childName, 'NotFoundError');
|
||||
},
|
||||
removeEntry: async (childName) => {
|
||||
if (node[childName]) {
|
||||
delete node[childName];
|
||||
return;
|
||||
}
|
||||
throw new DOMException('Not found: ' + childName, 'NotFoundError');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const rootHandle = makeDirHandle(filesystem, 'KOBOeReader', '');
|
||||
window.showDirectoryPicker = async () => rootHandle;
|
||||
}, { hasNickelMenu: opts.hasNickelMenu || false, firmware, serial });
|
||||
}, {
|
||||
hasNickelMenu: opts.hasNickelMenu || false,
|
||||
hasKoreader: opts.hasKoreader || false,
|
||||
hasReaderlyFonts: opts.hasReaderlyFonts || false,
|
||||
hasScreensaver: opts.hasScreensaver || false,
|
||||
firmware,
|
||||
serial,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -348,6 +348,10 @@ test.describe('NickelMenu', () => {
|
||||
|
||||
// Select remove
|
||||
await page.click('input[name="nm-option"][value="remove"]');
|
||||
|
||||
// No extra features installed — uninstall options should be hidden
|
||||
await expect(page.locator('#nm-uninstall-options')).toBeHidden();
|
||||
|
||||
await page.click('#btn-nm-next');
|
||||
|
||||
// Review step
|
||||
@@ -374,6 +378,58 @@ test.describe('NickelMenu', () => {
|
||||
const uninstallExists = await mockPathExists(page, '.adds', 'nm', 'uninstall');
|
||||
expect(uninstallExists, '.adds/nm/uninstall should exist').toBe(true);
|
||||
});
|
||||
|
||||
test('with device — remove NickelMenu with feature cleanup', async ({ page }) => {
|
||||
test.skip(!hasNickelMenuAssets(), 'NickelMenu assets not found in webroot');
|
||||
|
||||
await connectMockDevice(page, {
|
||||
hasNickelMenu: true,
|
||||
hasKoreader: true,
|
||||
hasReaderlyFonts: true,
|
||||
hasScreensaver: true,
|
||||
});
|
||||
|
||||
await page.click('#btn-device-next');
|
||||
await page.click('#btn-mode-next');
|
||||
|
||||
// Select remove
|
||||
await page.click('input[name="nm-option"][value="remove"]');
|
||||
|
||||
// Uninstall checkboxes should appear for all 3 detected features
|
||||
await expect(page.locator('#nm-uninstall-options')).not.toBeHidden();
|
||||
await expect(page.locator('input[name="nm-uninstall-koreader"]')).toBeChecked();
|
||||
await expect(page.locator('input[name="nm-uninstall-readerly-fonts"]')).toBeChecked();
|
||||
await expect(page.locator('input[name="nm-uninstall-screensaver"]')).toBeChecked();
|
||||
|
||||
// Uncheck screensaver (keep it)
|
||||
await page.uncheck('input[name="nm-uninstall-screensaver"]');
|
||||
|
||||
await page.click('#btn-nm-next');
|
||||
|
||||
// Review should list KOReader and Readerly but not Screensaver
|
||||
await expect(page.locator('#nm-review-summary')).toContainText('removal');
|
||||
await expect(page.locator('#nm-review-list')).toContainText('KOReader');
|
||||
await expect(page.locator('#nm-review-list')).toContainText('Readerly');
|
||||
await expect(page.locator('#nm-review-list')).not.toContainText('Screensaver');
|
||||
|
||||
// Execute removal
|
||||
await page.click('#btn-nm-write');
|
||||
await expect(page.locator('#step-nm-done')).toBeVisible({ timeout: 30_000 });
|
||||
await expect(page.locator('#nm-done-status')).toContainText('removed');
|
||||
|
||||
// NickelMenu uninstall marker should exist
|
||||
expect(await mockPathExists(page, '.adds', 'nm', 'uninstall')).toBe(true);
|
||||
|
||||
// KOReader directory should be removed
|
||||
expect(await mockPathExists(page, '.adds', 'koreader')).toBe(false);
|
||||
|
||||
// Readerly fonts should be removed
|
||||
expect(await mockPathExists(page, 'fonts', 'KF_Readerly-Regular.ttf')).toBe(false);
|
||||
expect(await mockPathExists(page, 'fonts', 'KF_Readerly-Bold.ttf')).toBe(false);
|
||||
|
||||
// Screensaver should NOT be removed (unchecked)
|
||||
expect(await mockPathExists(page, '.kobo', 'screensaver', 'moon.png')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
Reference in New Issue
Block a user