101 lines
6.8 KiB
JavaScript
101 lines
6.8 KiB
JavaScript
// End-to-end check of where "Today" puts the daily note. Run with `bun run test:e2e`.
|
|
const { app, BrowserWindow } = require('electron');
|
|
const path = require('path');
|
|
const os = require('os');
|
|
const fs = require('fs');
|
|
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ink-e2e-daily-'));
|
|
const vault = path.join(tmp, 'Vault');
|
|
fs.mkdirSync(path.join(vault, 'Private', 'Daily'), { recursive: true });
|
|
fs.writeFileSync(path.join(vault, 'Private.md'), 'Private stuff\n');
|
|
fs.writeFileSync(path.join(vault, 'Private', 'Daily.md'), 'My journal\n');
|
|
fs.writeFileSync(path.join(vault, 'Private', 'Daily', '2020-01-01.md'), 'An old day\n');
|
|
app.setPath('userData', tmp);
|
|
fs.writeFileSync(path.join(tmp, 'settings.json'), JSON.stringify({ vault, lastPage: 'Private', theme: 'dark', bounds: { width: 1100, height: 760 } }));
|
|
require('../electron/main.cjs');
|
|
|
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
const failures = [];
|
|
const check = (name, ok, extra = '') => {
|
|
console.log(`${ok ? 'PASS' : 'FAIL'} ${name}${extra ? ' — ' + extra : ''}`);
|
|
if (!ok) failures.push(name);
|
|
};
|
|
const z = (n) => String(n).padStart(2, '0');
|
|
const d = new Date();
|
|
const TODAY = `${d.getFullYear()}-${z(d.getMonth() + 1)}-${z(d.getDate())}`;
|
|
|
|
app.whenReady().then(async () => {
|
|
let win;
|
|
for (let i = 0; i < 80 && !(win = BrowserWindow.getAllWindows()[0]); i++) await sleep(100);
|
|
const wc = win.webContents;
|
|
if (wc.isLoading()) await new Promise((r) => wc.once('did-finish-load', r));
|
|
const js = (code) => wc.executeJavaScript(`(async () => { ${code} })()`);
|
|
const m = (type, x, y) => wc.sendInputEvent({ type, x: Math.round(x), y: Math.round(y), button: 'left', clickCount: 1 });
|
|
const box = (sel) => js(`const e = ${sel}; if (!e) return null; const r = e.getBoundingClientRect(); return { cx: r.x + r.width / 2, cy: r.y + r.height / 2 }`);
|
|
const click = async (x, y) => { m('mouseMove', x, y); m('mouseDown', x, y); m('mouseUp', x, y); await sleep(300); };
|
|
const type = async (t) => { for (const ch of t) { wc.sendInputEvent({ type: 'char', keyCode: ch }); await sleep(30); } await sleep(250); };
|
|
const key = async (keyCode) => { wc.sendInputEvent({ type: 'keyDown', keyCode }); wc.sendInputEvent({ type: 'keyUp', keyCode }); await sleep(250); };
|
|
const saved = () => JSON.parse(fs.readFileSync(path.join(tmp, 'settings.json'), 'utf8'));
|
|
const today = async () => {
|
|
await js(`[...document.querySelectorAll('.sidebar .qa')].find((b) => b.textContent.includes('Today')).click()`);
|
|
await sleep(1500);
|
|
};
|
|
|
|
try {
|
|
await sleep(2200);
|
|
await today();
|
|
check('"Today" uses the Daily folder where it already is, not a new one at the top', fs.existsSync(path.join(vault, 'Private', 'Daily', `${TODAY}.md`)) && !fs.existsSync(path.join(vault, 'Daily')) && !fs.existsSync(path.join(vault, 'Daily.md')));
|
|
check('...and opens it', (await js(`return document.querySelector('.tree .row.active')?.dataset.id`)) === `Private/Daily/${TODAY}`);
|
|
|
|
// choose another folder in Settings
|
|
await js(`[...document.querySelectorAll('.sidebar button')].find((b) => b.getAttribute('aria-label') === 'Settings').click()`);
|
|
await sleep(500);
|
|
check('Settings shows the folder it found', (await js(`return document.querySelector('input[aria-label="Daily notes folder"]')?.placeholder`)) === 'Private/Daily');
|
|
const field = await box(`document.querySelector('input[aria-label="Daily notes folder"]')`);
|
|
await click(field.cx, field.cy);
|
|
check('clicking the field lists the folders, with "find automatically" first', await js(`const l = [...document.querySelectorAll('.fp-list .mi')].map((b) => b.textContent.trim()); return l[0].startsWith('Find automatically') && l.some((t) => t.startsWith('Daily')) && l.some((t) => t.startsWith('Private'))`));
|
|
await type('dai');
|
|
check('typing narrows it, best matches first', await js(`const l = [...document.querySelectorAll('.fp-list .mi')].map((b) => b.querySelector('.mi-label').textContent.trim()); return l.length >= 2 && l[0] === 'Daily' && !l.includes('Private') && l[l.length - 1].startsWith('Use')`));
|
|
await key('Escape');
|
|
check('Escape closes the list and keeps the dialog', !(await js(`return !!document.querySelector('.fp-list')`)) && !!(await js(`return !!document.querySelector('.settings')`)));
|
|
await click(field.cx, field.cy);
|
|
await js(`const i = document.querySelector('input[aria-label="Daily notes folder"]'); i.value = ''; i.dispatchEvent(new Event('input', { bubbles: true }));`);
|
|
await type(' Journal / Days ');
|
|
check('a folder that does not exist yet can be used as typed, tidied', await js(`const l = [...document.querySelectorAll('.fp-list .mi')]; return l[l.length - 1].textContent.includes('Use “Journal/Days”')`));
|
|
await key('Return');
|
|
await sleep(600);
|
|
check('Enter keeps it', (await js(`return document.querySelector('input[aria-label="Daily notes folder"]').value`)) === 'Journal/Days');
|
|
const vkey = Object.keys(saved().vaults || {})[0];
|
|
check('...and remembers it with the notes folder', saved().vaults[vkey].dailyFolder === 'Journal/Days', JSON.stringify(saved().vaults));
|
|
// picking an existing folder from the list
|
|
await click(field.cx, field.cy);
|
|
await type('priv');
|
|
const row = await box(`[...document.querySelectorAll('.fp-list .mi')].find((b) => b.querySelector('.mi-label').textContent.trim() === 'Private')`);
|
|
await click(row.cx, row.cy);
|
|
await sleep(500);
|
|
check('clicking a folder in the list chooses it', saved().vaults[vkey].dailyFolder === 'Private' && !(await js(`return !!document.querySelector('.fp-list')`)));
|
|
await click(field.cx, field.cy);
|
|
await type('Journal/Days');
|
|
await key('Return');
|
|
await sleep(500);
|
|
await js(`document.querySelector('.settings [aria-label="Close"]').click()`);
|
|
await sleep(400);
|
|
fs.rmSync(path.join(vault, 'Private', 'Daily', `${TODAY}.md`));
|
|
await today();
|
|
check('"Today" now makes the note in the chosen folder', fs.existsSync(path.join(vault, 'Journal', 'Days', `${TODAY}.md`)) && !fs.existsSync(path.join(vault, 'Private', 'Daily', `${TODAY}.md`)));
|
|
check('...and nothing is made at the top', !fs.existsSync(path.join(vault, 'Daily')));
|
|
|
|
// back to automatic
|
|
await js(`[...document.querySelectorAll('.sidebar button')].find((b) => b.getAttribute('aria-label') === 'Settings').click()`);
|
|
await sleep(500);
|
|
await js(`document.querySelector('.set-link').click()`);
|
|
await sleep(500);
|
|
check('"Find it automatically" goes back', (await js(`return document.querySelector('input[aria-label="Daily notes folder"]').value`)) === '' && saved().vaults[vkey].dailyFolder === null);
|
|
} catch (err) {
|
|
check('harness', false, err.stack);
|
|
}
|
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
console.log(failures.length ? `\n${failures.length} check(s) failed` : '\ndaily e2e passed!');
|
|
app.exit(failures.length ? 1 : 0);
|
|
});
|