The Book Downloads card has an "Enable OPDS" box. In the proxy mode, it also shows the user name for the reader and a field to set the OPDS password. The field is grey until the box is checked. Disabled text fields now look grey.
128 lines
6.8 KiB
JavaScript
128 lines
6.8 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { test } from 'node:test';
|
|
import { Element, change, click, field, find, install, nodes, section, server, settle } from './flow-helpers.mjs';
|
|
|
|
install();
|
|
const { settingsPage } = await import('../../bindery/static/js/settings.js');
|
|
|
|
async function open(t, settings, authMode = 'proxy') {
|
|
install();
|
|
t.mock.timers.enable({ apis: ['setTimeout'] });
|
|
const backend = server(t);
|
|
const stored = { download_template: '{title}', download_date_format: '%Y', personal_ini: '', ...settings };
|
|
backend.on('GET', 'settings', stored);
|
|
backend.on('GET', 'rules', { rules: [] });
|
|
backend.on('GET', 'stories', []);
|
|
backend.on('PUT', 'settings', ({ body }) => ({ ...stored, ...body }));
|
|
backend.on('PUT', 'settings/opds-password', { opds_user: 'alice', opds_password_set: true });
|
|
const main = new Element('main');
|
|
settingsPage(main, {}, { cwa_enabled: false, download_fields: {}, auth_mode: authMode });
|
|
await settle();
|
|
return { backend, main, card: section(main, 'Book Downloads') };
|
|
}
|
|
|
|
for (const enabled of [false, true]) {
|
|
test(`OPDS loads ${enabled}, appears first in Book Downloads, and saves both states`, async (t) => {
|
|
const { backend, main, card } = await open(t, { opds_enabled: enabled });
|
|
const toggle = field(card, 'opds-enabled');
|
|
assert.equal(toggle.checked, enabled);
|
|
assert.equal(card.children[1].tagName, 'label');
|
|
assert.equal(card.children[1].children[0], toggle);
|
|
assert.equal(card.children[1].textContent, ' Enable OPDS');
|
|
assert.equal(toggle.getAttribute('aria-describedby'), 'opds-note');
|
|
assert.match(field(card, 'opds-note').textContent, /off by default/);
|
|
assert.equal(find(field(card, 'opds-note'), 'a', 'the OPDS catalog').getAttribute('href'), 'opds');
|
|
assert.equal(nodes(main).filter((node) => node.getAttribute('id') === 'opds-enabled').length, 1);
|
|
for (const value of [!enabled, enabled]) {
|
|
change(toggle, value);
|
|
await click(card, 'Save');
|
|
assert.deepEqual(backend.sent('PUT', 'settings').at(-1).body, {
|
|
opds_enabled: value, download_template: '{title}', download_date_format: '%Y',
|
|
});
|
|
assert.equal(toggle.checked, value);
|
|
}
|
|
backend.on('PUT', 'settings', { opds_enabled: false, download_template: '{title}', download_date_format: '%Y' });
|
|
change(toggle, true);
|
|
await click(card, 'Save');
|
|
assert.equal(toggle.checked, false, 'The saved response sets the checkbox state');
|
|
});
|
|
}
|
|
|
|
const LOGIN = {
|
|
none: /Bindery asks for no login, so the catalog needs none/,
|
|
local: /sends your Bindery user name and password/,
|
|
cwa: /sends your CWA user name and password/,
|
|
proxy: /The proxy skips its login for the catalog.*Each user sets an OPDS password.*user name from the proxy/,
|
|
};
|
|
for (const [mode, text] of Object.entries(LOGIN)) {
|
|
test(`the note names the login of the ${mode} mode, and only the proxy mode shows the password`, async (t) => {
|
|
const { card } = await open(t, { opds_enabled: true, opds_password_set: false, opds_user: 'alice' }, mode);
|
|
assert.match(field(card, 'opds-note').textContent, text);
|
|
assert.doesNotMatch(field(card, 'opds-note').textContent, /BINDERY_API_KEY|Bearer|X-Api-Key/);
|
|
for (const id of ['opds-user', 'opds-password', 'opds-password-status']) {
|
|
assert.equal(field(card, id) !== undefined, mode === 'proxy', id);
|
|
}
|
|
assert.equal(find(card, 'button', 'Set password') !== undefined, mode === 'proxy');
|
|
});
|
|
}
|
|
|
|
test('the password field is grey until the box is checked, and follows the box at once', async (t) => {
|
|
const { card } = await open(t, { opds_enabled: false, opds_password_set: true, opds_user: 'alice' });
|
|
const password = field(card, 'opds-password');
|
|
const button = find(card, 'button', 'Reset password');
|
|
assert.equal(password.disabled, true);
|
|
assert.equal(button.disabled, true);
|
|
change(field(card, 'opds-enabled'), true);
|
|
assert.equal(password.disabled, false);
|
|
assert.equal(button.disabled, false);
|
|
change(field(card, 'opds-enabled'), false);
|
|
assert.equal(password.disabled, true);
|
|
assert.equal(button.disabled, true);
|
|
});
|
|
|
|
for (const isSet of [false, true]) {
|
|
test(`the OPDS password ${isSet ? 'is set' : 'is not set'}, and the button sets or resets it`, async (t) => {
|
|
const { backend, card } = await open(t, { opds_enabled: true, opds_password_set: isSet, opds_user: 'alice' });
|
|
const password = field(card, 'opds-password');
|
|
const status = field(card, 'opds-password-status');
|
|
const user = field(card, 'opds-user');
|
|
assert.equal(user.value, 'alice');
|
|
assert.equal(user.getAttribute('readonly'), '');
|
|
assert.equal(user.disabled, false, 'The user name stays selectable');
|
|
assert.equal(user.getAttribute('aria-describedby'), 'opds-password-status');
|
|
assert.equal(find(card, 'label', 'OPDS user name').getAttribute('for'), 'opds-user');
|
|
assert.equal(find(card, 'label', 'OPDS password').getAttribute('for'), 'opds-password');
|
|
assert.equal(password.disabled, false);
|
|
assert.equal(password.getAttribute('type'), 'password');
|
|
assert.equal(password.getAttribute('autocomplete'), 'new-password');
|
|
assert.equal(password.getAttribute('minlength'), '8');
|
|
assert.equal(password.value, '');
|
|
assert.match(status.textContent, /enter the user name and the password in your reader/i);
|
|
assert.match(status.textContent, isSet ? /You have an OPDS password/ : /You have no OPDS password yet/);
|
|
assert.ok(find(card, 'button', isSet ? 'Reset password' : 'Set password'));
|
|
password.value = 'long enough';
|
|
await click(card, isSet ? 'Reset password' : 'Set password');
|
|
assert.deepEqual(backend.sent('PUT', 'settings/opds-password')[0].body, { password: 'long enough' });
|
|
assert.equal(password.value, '', 'The field is empty after the save');
|
|
assert.match(status.textContent, /You have an OPDS password/);
|
|
assert.equal(password.disabled, false);
|
|
assert.ok(find(card, 'button', 'Reset password'));
|
|
// The Save button of the card never sends the password.
|
|
password.value = 'not sent';
|
|
await click(card, 'Save');
|
|
assert.equal(backend.sent('PUT', 'settings/opds-password').length, 1);
|
|
assert.equal('password' in backend.sent('PUT', 'settings')[0].body, false);
|
|
assert.equal(password.disabled, false, 'A save keeps the field in step with the box');
|
|
});
|
|
}
|
|
|
|
test('a rejected OPDS password keeps the field and the status', async (t) => {
|
|
const { backend, card } = await open(t, { opds_enabled: true, opds_password_set: false });
|
|
backend.on('PUT', 'settings/opds-password', { error: 'The OPDS password must be text of 8 to 256 characters' }, 400);
|
|
field(card, 'opds-password').value = 'short';
|
|
await click(card, 'Set password');
|
|
assert.equal(field(card, 'opds-password').value, 'short');
|
|
assert.match(field(card, 'opds-password-status').textContent, /You have no OPDS password yet/);
|
|
assert.ok(find(card, 'button', 'Set password'));
|
|
});
|