aboutsummaryrefslogtreecommitdiffstats
path: root/tools/thread-reply-test.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/thread-reply-test.js')
-rw-r--r--tools/thread-reply-test.js16
1 files changed, 11 insertions, 5 deletions
diff --git a/tools/thread-reply-test.js b/tools/thread-reply-test.js
index 4362468..16b6f50 100644
--- a/tools/thread-reply-test.js
+++ b/tools/thread-reply-test.js
@@ -7,6 +7,7 @@ const dom = app.slice(app.indexOf('function h(tag,'), app.indexOf('// ----------
const entry = `
import { messagesFeature } from './src/features/messages.js';
import { createThreadStore } from './src/thread-cache.js';
+import './src/rich-text.js'; // <coinos-text>, the reply field (app.js registers it)
${dom}
const author = 'a'.repeat(64), mine = 'b'.repeat(64), rootId = 'c'.repeat(64);
const root = { id: rootId, pubkey: author, kind: 1, content: 'Root post', tags: [], created_at: 1 };
@@ -14,10 +15,12 @@ const reply = { ...root, id: 'd'.repeat(64), content: 'The reply you tapped', ta
const other = { ...reply, id: 'e'.repeat(64), content: 'Another reply not returned by the relay', created_at: 3 };
const ui = { screen: 'wallet' }, waiting = [];
window.sent = [];
-window.query = filter => filter.kinds?.[0] === 1 && (filter.ids || filter['#e']) ? new Promise(resolve => waiting.push({ filter, resolve })) : Promise.resolve([]);
+// the root (asked for by id, any kind) and its replies are held until the test lets them go
+window.query = filter => filter.ids || (filter.kinds?.[0] === 1 && filter['#e']) ? new Promise(resolve => waiting.push({ filter, resolve })) : Promise.resolve([]);
const signer = { signEvent: async e => ({ ...e, id: 'f'.repeat(64), pubkey: mine }) };
let feature;
-const wallet = { loaded: true, nostrRelays: () => [], loadFeatureState: (k, d) => d, saveFeatureState() {} };
+// (a wallet is open: without one the app is a visitor's, and Reply asks you to sign in)
+const wallet = { xpub: 'test-wallet', loaded: true, nostrRelays: () => [], loadFeatureState: (k, d) => d, saveFeatureState() {} };
function render() {
if (!feature) return;
document.querySelector('#app').replaceChildren(feature.screenView() || feature.row(author, reply, 'Someone'));
@@ -26,6 +29,7 @@ feature = messagesFeature({ h, wallet, ui, render, toast() {}, brandHeader: () =
? h('div', { style: 'height:60px' }) : null,
hook: k => k === 'nostrLoginIdentity' ? { pubkey: mine, signer } : null });
window.test = { ui, reply, other, root, render, waiting, showNav: false,
+ held: () => waiting.some(q => q.filter.ids) && waiting.some(q => q.filter['#e']),
stable: () => feature.testStable(),
seedFace: () => createThreadStore().save({ root, replies: [reply] }, reply.id, {
[author]: { name: 'Nostrich', picture: 'https://example.com/nostrich.webp', eventAt: 10, t: Date.now(),
@@ -75,10 +79,12 @@ try {
check('Reply immediately shows its composer beneath the tapped post', await inline());
check('the input receives focus before relay queries finish', await page.evaluate(() => document.activeElement.matches('.thread-reply-input')));
await page.type('.thread-reply-input', 'A reply before the root loads');
- await page.click('.thread-reply-send');
+ // (one atomic tap: a repaint landing between finding the button and clicking it replaces it)
+ await page.waitForFunction(() => !document.querySelector('.thread-reply-send')?.disabled);
+ await page.evaluate(() => document.querySelector('.thread-reply-send').click());
await page.waitForFunction(() => sent.length === 1);
check('publishing targets the selected reply and its original root', await page.evaluate(() => sent[0].tags.some(t => t[0] === 'e' && t[1] === test.reply.id && t[3] === 'reply') && sent[0].tags.some(t => t[0] === 'e' && t[1] === test.root.id && t[3] === 'root')));
- await page.waitForFunction(() => test.waiting.length === 2);
+ await page.waitForFunction(() => test.held());
await page.evaluate(() => test.release());
await page.waitForFunction(() => document.body.innerText.includes('Root post'));
// the composer folds away once the reply is sent; the tapped reply itself stays
@@ -90,7 +96,7 @@ try {
check('Reply leaves the covering profile and inserts an uncached reply into the thread', await inline() && await page.evaluate(() => !test.ui.profOverThread && document.activeElement.matches('.thread-reply-input')));
await page.evaluate(() => test.missing());
await page.click('#outside .note-act');
- await page.waitForFunction(() => test.waiting.length === 2);
+ await page.waitForFunction(() => test.held());
await page.evaluate(() => test.empty());
await page.waitForFunction(() => !document.querySelector('#app .spinner'));
check('an unavailable root still leaves the selected post replyable', await inline());