aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/feed-custom-test.js27
-rw-r--r--tools/feed-follow-test.js43
-rw-r--r--tools/feed-live-test.js37
-rw-r--r--tools/feed-window-dom-test.js5
-rw-r--r--tools/moderation-test.js14
-rw-r--r--tools/poll-test.js3
6 files changed, 73 insertions, 56 deletions
diff --git a/tools/feed-custom-test.js b/tools/feed-custom-test.js
index 039b166..c2c94de 100644
--- a/tools/feed-custom-test.js
+++ b/tools/feed-custom-test.js
@@ -73,7 +73,10 @@ const errs = [];
page.on('pageerror', (e) => errs.push(String(e)));
const click = (t) => page.evaluate((x) => { const e = [...document.querySelectorAll('button')].find((n) => n.textContent.trim().toLowerCase().includes(x)); if (e) { e.click(); return true; } return false; }, t);
const waitText = async (x, ms = 25000) => { for (let i = 0; i < ms / 250; i++) { if ((await page.evaluate(() => document.body.innerText)).toLowerCase().includes(x)) return true; await sleep(250); } return false; };
-const chips = () => page.evaluate(() => [...document.querySelectorAll('.feed-chip')].map((c) => (c.classList.contains('on') ? '*' : '') + c.textContent.trim()));
+// the feeds' own chips (not the All / Images / … view switch under them)
+const chips = () => page.evaluate(() => [...document.querySelectorAll('.feed-chips > .feed-chip')].map((c) => (c.classList.contains('on') ? '*' : '') + c.textContent.trim()));
+// the Feed is a tab in the bottom nav (it was a row on the chat home)
+const openFeed = () => page.evaluate(() => [...document.querySelectorAll('.app-nav-button')].find((b) => b.getAttribute('aria-label') === 'Feed')?.click());
const type = async (sel, text) => {
await page.evaluate((q) => { const i = document.querySelector(q); i.value = ''; i.dispatchEvent(new Event('input', { bubbles: true })); }, sel);
await page.click(sel); await page.type(sel, text);
@@ -99,12 +102,11 @@ try {
await page.evaluate(([k, pk, ns]) => {
localStorage.setItem(k + ':follows', JSON.stringify({ tags: [['p', pk]], c: '', at: Math.floor(Date.now() / 1000) }));
localStorage.setItem(k + ':feedNotes', JSON.stringify(ns));
+ localStorage.setItem('btc-wallet-feed:' + k, 'following'); // a wallet with no feed remembered opens on Popular
}, [base, AUTHOR, seeded]);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); });
- await sleep(800);
- await page.evaluate(() => { const e = [...document.querySelectorAll('.item')].find((n) => /feed/i.test(n.textContent)); if (e) e.click(); });
+ await openFeed();
await sleep(1200);
check('the feed opens on Following, with a + chip', JSON.stringify(await chips()) === JSON.stringify(['*Following', 'Popular', '#gardenstr', '+']), JSON.stringify(await chips()));
@@ -112,7 +114,7 @@ try {
await page.click('.feed-chip.add'); await sleep(300);
check('the editor opens', await waitText('new feed', 3000));
await type('input[placeholder="e.g. Bitcoin builders"]', 'Coin talk');
- await page.click('input[type=checkbox]');
+ await page.click('input[type=checkbox]:not(.feed-all-toggle)'); // everyone I follow (the first box is the relays' every-post one)
await type('input[placeholder="#bitcoin #nostr"]', '#Bitcoin, lightning');
await click('save'); await sleep(1500);
check('the new feed is on screen and selected', JSON.stringify(await chips()) === JSON.stringify(['Following', 'Popular', '#gardenstr', '*Coin talk', '+']), JSON.stringify(await chips()));
@@ -157,15 +159,18 @@ try {
console.log('\n[the feeds survive a reload; a feed can be deleted]');
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); }); await sleep(800);
- await page.evaluate(() => { const e = [...document.querySelectorAll('.item')].find((n) => /feed/i.test(n.textContent)); if (e) e.click(); }); await sleep(1200);
- check('the saved feeds are still there; the session topic is not', JSON.stringify(await chips()) === JSON.stringify(['*Following', 'Popular', '#gardenstr', 'Coin talk', 'Pack feed', '+']), JSON.stringify(await chips()));
- check('the home list shows the pack feed with its pack', await page.evaluate(() => { const b = document.querySelector('.chat-back'); if (b) b.click(); return !!b; }) && await waitText('test pack', 3000));
- await page.evaluate(() => { const e = [...document.querySelectorAll('.item')].find((n) => (n.querySelector('.chat-name') || {}).textContent === 'Feed'); if (e) e.click(); }); await sleep(800);
+ await openFeed(); await sleep(1200);
+ // (the feed you were on is remembered: the pack feed, saved last)
+ check('the saved feeds are still there; the session topic is not', JSON.stringify(await chips()) === JSON.stringify(['Following', 'Popular', '#gardenstr', 'Coin talk', '*Pack feed', '+']), JSON.stringify(await chips()));
+ // (the chat home no longer lists the feed with its summary: its editor shows the pack)
+ await page.click('[aria-label="Feed options"]'); await sleep(300);
+ await page.evaluate(() => [...document.querySelectorAll('.msg-sheet button')].find((b) => /edit feed/i.test(b.textContent)).click()); await sleep(400);
+ check('the pack feed kept its pack', await waitText('test pack', 3000));
+ await page.click('.chat-back'); await sleep(600);
await page.evaluate(() => [...document.querySelectorAll('.feed-chip')].find((c) => c.textContent.trim() === 'Coin talk').click()); await sleep(800);
await page.click('[aria-label="Feed options"]'); await sleep(300); // the editor lives in the feed's ⋯ menu now
await page.evaluate(() => [...document.querySelectorAll('.msg-sheet button')].find((b) => /edit feed/i.test(b.textContent)).click()); await sleep(400);
- check('the editor shows what was saved', await page.evaluate(() => document.querySelector('input[placeholder="#bitcoin #nostr"]').value === '#bitcoin #lightning' && document.querySelector('input[type=checkbox]').checked));
+ check('the editor shows what was saved', await page.evaluate(() => document.querySelector('input[placeholder="#bitcoin #nostr"]').value === '#bitcoin #lightning' && document.querySelector('input[type=checkbox]:not(.feed-all-toggle)').checked));
await click('delete feed'); await sleep(1000);
check('deleting it lands back on Following', JSON.stringify(await chips()) === JSON.stringify(['*Following', 'Popular', '#gardenstr', 'Pack feed', '+']), JSON.stringify(await chips()));
check('no page errors', errs.length === 0, errs.slice(0, 2).join(' | '));
diff --git a/tools/feed-follow-test.js b/tools/feed-follow-test.js
index 50a572b..bae06a9 100644
--- a/tools/feed-follow-test.js
+++ b/tools/feed-follow-test.js
@@ -20,7 +20,9 @@ const server = Bun.serve({ port: 5237, fetch: () => new Response(html, { headers
const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', headless: 'new', args: ['--no-sandbox'] });
const page = await browser.newPage();
const click = (t) => page.evaluate((x) => { const e = [...document.querySelectorAll('button')].find((n) => n.textContent.trim().toLowerCase().includes(x)); if (e) { e.click(); return true; } return false; }, t);
-const clickItem = (t) => page.evaluate((x) => { const e = [...document.querySelectorAll('.item, button')].find((n) => n.textContent.trim().toLowerCase().includes(x)); if (e) { e.click(); return true; } return false; }, t);
+// the Feed is a tab in the bottom nav (it used to be offered on the messages home)
+const openFeed = () => page.evaluate(() => { const b = [...document.querySelectorAll('.app-nav-button')].find((e) => e.getAttribute('aria-label') === 'Feed'); if (b) b.click(); return !!b; });
+const chip = (name) => page.evaluate((n) => { const e = [...document.querySelectorAll('.feed-chips > .feed-chip')].find((b) => b.textContent.trim() === n); if (e) e.click(); return !!e; }, name);
const text = () => page.evaluate(() => document.body.innerText);
const waitText = async (x, ms = 25000) => { for (let i = 0; i < ms / 250; i++) { if ((await text()).toLowerCase().includes(x)) return true; await sleep(250); } return false; };
const FOLLOWED = 'e'.repeat(63) + '1';
@@ -40,12 +42,10 @@ try {
await waitText('receive', 20000);
const base = cacheKeyFor(mnemonic + '\n');
- // chat → the feed is offered before the conversations
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); });
- await sleep(1200);
- check('the feed is on the messages home', /follow people to fill this/i.test(await text()), (await text()).split('\n').slice(0, 6).join(' | '));
-
- await clickItem('feed');
+ check('the bottom nav has a Feed tab', await openFeed());
+ await sleep(1000);
+ // a new wallet opens on Popular; Following is the people you follow
+ check('...whose chips include Following', await chip('Following'));
await sleep(1000);
check('a wallet that follows nobody is told so', /don't follow anyone yet/i.test(await text()));
check('...and offered somewhere to start', /find people/i.test(await text()));
@@ -56,9 +56,11 @@ try {
}, [base, FOLLOWED]);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); });
+ await openFeed();
await sleep(1200);
- check('the follow count shows on the messages home', /posts from the one person you follow/i.test(await text()), (await text()).match(/Posts from[^\n]*/)?.[0] || 'no line');
+ // (the feed you were on, Following, is remembered)
+ check('Following no longer says you follow nobody', /\bFollowing\b/.test(await page.evaluate(() => document.querySelector('.feed-chips > .feed-chip.on')?.textContent || ''))
+ && !/don't follow anyone yet/i.test(await text()));
// and their own profile page knows we follow them
await page.goto('http://localhost:5237/' + npubEncode(FOLLOWED), { waitUntil: 'domcontentloaded' });
@@ -89,9 +91,7 @@ try {
}, [base, FOLLOWED, OTHER]);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); });
- await sleep(1000);
- await clickItem('feed');
+ await openFeed();
await sleep(6000);
const dialled = await page.evaluate(() => window.__dialled || []);
check('each author is read on their own write relay',
@@ -114,35 +114,32 @@ try {
}, [base, FOLLOWED]);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); });
- await sleep(1000);
- await clickItem('feed');
+ await openFeed();
await sleep(6000);
const wide = await page.evaluate(() => window.__dialled || []);
const hit = [1, 2, 3, 4, 5, 6].filter((n) => wide.some((u) => u.includes('r' + n + '.example.invalid')));
check('an author who publishes to six relays is read on all six',
hit.length === 6, 'reached ' + (hit.join(',') || 'none'));
- // The feed opens at twenty posts and grows as you reach the bottom, however
- // many it is holding.
+ // The feed opens at ten posts and grows as you reach the bottom, however
+ // many it is holding. (Tall posts: a page of short ones doesn't reach the
+ // distance from the bottom where the next page is read.)
await page.evaluate((k) => {
const notes = [];
const now = Math.floor(Date.now() / 1000);
- for (let i = 0; i < 60; i++) notes.push({ id: String(i).padStart(64, '0'), pubkey: 'f'.repeat(64), kind: 1, created_at: now - i * 60, content: 'post ' + i, tags: [] });
+ for (let i = 0; i < 60; i++) notes.push({ id: String(i).padStart(64, '0'), pubkey: 'f'.repeat(64), kind: 1, created_at: now - i * 60, content: 'post ' + i + ' ' + 'with enough words to stand tall '.repeat(30), tags: [] });
localStorage.setItem(k + ':feedNotes', JSON.stringify(notes));
}, base);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); });
- await sleep(1000);
- await clickItem('feed');
+ await openFeed();
await sleep(1500);
const first = await page.evaluate(() => document.querySelectorAll('.notes-feed > .row').length);
- check('the feed opens at twenty posts, not sixty', first === 20, first + ' rows');
+ check('the feed opens at ten posts, not sixty', first === 10, first + ' rows');
await page.evaluate(() => window.scrollTo(0, document.documentElement.scrollHeight));
await sleep(1200);
const second = await page.evaluate(() => document.querySelectorAll('.notes-feed > .row').length);
- check('reaching the bottom shows twenty more', second === 40, second + ' rows');
+ check('reaching the bottom shows ten more', second === 20, second + ' rows');
} finally { await browser.close(); server.stop(true); }
console.log(ok ? '\n✅ follows and feed' : '\n❌ failed');
process.exit(ok ? 0 : 1);
diff --git a/tools/feed-live-test.js b/tools/feed-live-test.js
index 9f98fde..8f80d46 100644
--- a/tools/feed-live-test.js
+++ b/tools/feed-live-test.js
@@ -105,12 +105,12 @@ try {
localStorage.setItem(k + ':follows', JSON.stringify({ tags: [['p', pk]], c: '', at: Math.floor(Date.now() / 1000) }));
localStorage.setItem(k + ':feedNotes', JSON.stringify(ns));
localStorage.setItem(k + ':profiles', JSON.stringify({ [pk]: { name: 'Test Author', t: Date.now() } }));
+ localStorage.setItem('btc-wallet-feed:' + k, 'following'); // a new wallet would open on Popular
}, [base, AUTHOR, seeded]);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); });
- await sleep(1000);
- await page.evaluate(() => { const e = [...document.querySelectorAll('.item')].find((n) => /feed/i.test(n.textContent)); if (e) e.click(); });
+ // the Feed is a tab in the bottom nav (it was a row on the chat home)
+ await page.evaluate(() => [...document.querySelectorAll('.app-nav-button')].find((b) => b.getAttribute('aria-label') === 'Feed')?.click());
await sleep(4000);
check('the feed has posts in it', (await page.evaluate(() => document.querySelectorAll('.notes-feed > .row').length)) > 0);
@@ -144,8 +144,12 @@ try {
await page.evaluate(() => document.querySelector('.feed-new-pill').click());
await sleep(600);
- const opened = await page.evaluate(() => ({ y: Math.round(window.scrollY), pill: !!document.querySelector('.feed-new-pill') }));
- check('tapping it takes you up to the post', opened.y < 120, 'scrollY ' + opened.y);
+ // the pill lands on the (oldest) new post, at the top of the screen
+ const opened = await page.evaluate(() => {
+ const r = [...document.querySelectorAll('.notes-feed > .row')].find((n) => /BRAND NEW POST/.test(n.innerText));
+ return { top: r ? Math.round(r.getBoundingClientRect().top) : null, pill: !!document.querySelector('.feed-new-pill') };
+ });
+ check('tapping it takes you up to the post', opened.top !== null && opened.top >= 0 && opened.top < 120, 'post top ' + opened.top);
check('...and the pill is done', !opened.pill);
console.log('\n[scrolling back up on your own]');
@@ -238,6 +242,12 @@ try {
const r = [...document.querySelectorAll('.notes-feed > .row')].find((n) => eval(label)(n) === text);
return r ? { text, top: Math.round(r.getBoundingClientRect().top), y: Math.round(window.scrollY) } : null;
}, label.toString(), text);
+ // up to the top the way a reader goes, a screen at a time (one jump from
+ // far down lands before the rows up there are mounted again)
+ const scrollUp = async () => {
+ while (await page.evaluate(() => { scrollBy(0, -Math.min(scrollY, innerHeight)); return scrollY > 0; })) await sleep(80);
+ await sleep(600);
+ };
const topRow = () => page.evaluate(() => (document.querySelector('.notes-feed > .row') || {}).innerText || '');
console.log('\n[coming back after being away, a few new posts]');
@@ -260,23 +270,20 @@ try {
await page.evaluate(() => window.scrollTo(0, document.documentElement.scrollHeight));
await sleep(600);
check('...older posts that merely missed the cache went in quietly too', /not in the cache/.test(await feedText()));
- await page.evaluate(() => window.scrollTo(0, 0));
- await sleep(600);
+ await scrollUp();
check('...scrolling up reaches the newest post, and clears the pill', /CATCH-UP 1/.test(await topRow()) && !(await page.$('.feed-new-pill')), (await topRow()).slice(0, 40));
console.log('\n[coming back while sitting at the top]');
const wasTop = await anchor();
await away(() => [signed('AT-THE-TOP A', 0), signed('AT-THE-TOP B', 1)]);
const a2 = await rowAt(wasTop.text);
- check('the header and first post stay in place', !!wasTop && !!a2 && a2.text === wasTop.text && Math.abs(a2.top - wasTop.top) <= 2 && a2.y === wasTop.y,
+ // new posts go in above the first post, which is held where it was (the
+ // page grows upward, scrolled by what went in above it)
+ check('the first post stays in place', !!wasTop && !!a2 && a2.text === wasTop.text && Math.abs(a2.top - wasTop.top) <= 2,
JSON.stringify({ was: wasTop, now: a2 }));
- check('...new posts wait while the header is visible', !/AT-THE-TOP A/.test(await topRow()));
- await page.evaluate(() => {
- const first = document.querySelector('.notes-feed > .row');
- scrollBy(0, Math.ceil(first.getBoundingClientRect().top));
- });
- await sleep(600);
- check('...then arrive offscreen above it, with a notice', /AT-THE-TOP A/.test(await topRow()) && /2 new posts/i.test(await page.evaluate(() => document.querySelector('.feed-new-pill')?.textContent || '')));
+ const atTop = await rowAt('AT-THE-TOP A');
+ check('...the new posts went in above it', /AT-THE-TOP A/.test(await topRow()) && !!atTop && !!a2 && atTop.top < a2.top, JSON.stringify(atTop));
+ check('...with a notice', /2 new posts/i.test(await page.evaluate(() => document.querySelector('.feed-new-pill')?.textContent || '')));
console.log('\n[coming back after a long time away]');
await page.evaluate(() => window.scrollTo(0, 900));
diff --git a/tools/feed-window-dom-test.js b/tools/feed-window-dom-test.js
index 7f89785..72ca535 100644
--- a/tools/feed-window-dom-test.js
+++ b/tools/feed-window-dom-test.js
@@ -87,11 +87,12 @@ try {
localStorage.setItem(k + ':follows', JSON.stringify({ tags: [['p', pk]], c: '', at: Math.floor(Date.now() / 1000) }));
localStorage.setItem(k + ':feedNotes', JSON.stringify(ns));
localStorage.setItem(k + ':profiles', JSON.stringify({ [pk]: { name: 'Prolific Poster', t: Date.now() } }));
+ localStorage.setItem('btc-wallet-feed:' + k, 'following'); // a wallet with no feed remembered opens on Popular
}, [base, AUTHOR, seeded]);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); }); await sleep(800);
- await page.evaluate(() => { const e = [...document.querySelectorAll('.item')].find((n) => (n.querySelector('.chat-name') || {}).textContent === 'Feed'); if (e) e.click(); });
+ // the Feed is a tab in the bottom nav (it was a row on the chat home)
+ await page.evaluate(() => [...document.querySelectorAll('.app-nav-button')].find((b) => b.getAttribute('aria-label') === 'Feed')?.click());
await sleep(2500);
console.log('\n[a long scroll]');
check('the feed opens on its first posts', (await dom()).first === 'post number 1', JSON.stringify(await dom()));
diff --git a/tools/moderation-test.js b/tools/moderation-test.js
index 1f4deb8..d6df879 100644
--- a/tools/moderation-test.js
+++ b/tools/moderation-test.js
@@ -33,7 +33,12 @@ const REPLIES = [reply(OTHER, 'reply from ok person', 200), reply(MUTED, 'reply
const LONG = 'buy the dip now, best exchange ever, sign up with my link and get free sats today!!!';
const html = await buildHtml({ minify: true, pwa: false });
-const server = Bun.serve({ port: 5299, fetch: () => new Response(html, { headers: { 'content-type': 'text/html' } }) });
+// nos.lol (one of the relays the mute list is read from) is a stand-in
+// served here — an empty relay — so a real one that won't connect can't hold
+// the list back past the checks
+const server = Bun.serve({ port: 5299,
+ fetch: (req, srv) => (new URL(req.url).pathname === '/relay' && srv.upgrade(req) ? undefined : new Response(html, { headers: { 'content-type': 'text/html' } })),
+ websocket: { message: (ws, data) => { try { const m = JSON.parse(data); if (m[0] === 'REQ') ws.send(JSON.stringify(['EOSE', m[1]])); } catch {} } } });
const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', headless: 'new', args: ['--no-sandbox'] });
const page = await browser.newPage();
await page.evaluateOnNewDocument((fx) => {
@@ -46,6 +51,7 @@ await page.evaluateOnNewDocument((fx) => {
ws.dispatchEvent(new MessageEvent('message', { data: JSON.stringify(['EOSE', id]) }));
}, 0);
window.WebSocket = function (...a) {
+ if (/^wss:\/\/nos\.lol\/?$/.test(String(a[0]))) a[0] = 'ws://localhost:5299/relay';
const ws = new Real(...a);
const send = ws.send.bind(ws);
ws.send = (data) => {
@@ -96,9 +102,8 @@ const waitText = async (x, ms = 25000) => { for (let i = 0; i < ms / 250; i++) {
const waitFor = async (fn, ms = 10000) => { for (let i = 0; i < ms / 250; i++) { if (await page.evaluate(fn)) return true; await sleep(250); } return false; };
const has = async (x) => (await text()).includes(x);
const openFeed = async () => {
- await page.evaluate(() => { const b = [...document.querySelectorAll('button')].find((e) => /message/i.test(e.getAttribute('aria-label') || '')); if (b) b.click(); });
- await sleep(800);
- await page.evaluate(() => { const e = [...document.querySelectorAll('.item')].find((n) => (n.querySelector('.chat-name') || {}).textContent === 'Feed'); if (e) e.click(); });
+ // the Feed is a tab in the bottom nav (it was a row on the chat home)
+ await page.evaluate(() => [...document.querySelectorAll('.app-nav-button')].find((b) => b.getAttribute('aria-label') === 'Feed')?.click());
await sleep(1200);
};
@@ -122,6 +127,7 @@ try {
await page.evaluate(([k, pk, ns]) => {
localStorage.setItem(k + ':follows', JSON.stringify({ tags: [['p', pk]], c: '', at: Math.floor(Date.now() / 1000) }));
localStorage.setItem(k + ':feedNotes', JSON.stringify(ns));
+ localStorage.setItem('btc-wallet-feed:' + k, 'following'); // a wallet with no feed remembered opens on Popular
}, [base, AUTHOR.pk, seeded]);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
diff --git a/tools/poll-test.js b/tools/poll-test.js
index b88a4db..bc1715e 100644
--- a/tools/poll-test.js
+++ b/tools/poll-test.js
@@ -52,11 +52,12 @@ try {
const quoting = { id: 'd'.repeat(64), pubkey: q, kind: 1, created_at: now, content: 'vote on this nostr:' + ref, tags: [] };
localStorage.setItem(k + ':follows', JSON.stringify({ tags: [['p', poll.pubkey], ['p', q]], c: '', at: now }));
localStorage.setItem(k + ':feedNotes', JSON.stringify([quoting, poll]));
+ localStorage.setItem('btc-wallet-feed:' + k, 'following'); // a wallet with no feed remembered opens on Popular
localStorage.setItem(k + ':profiles', JSON.stringify({ [poll.pubkey]: { name: 'Poll Author', t: Date.now() }, [q]: { name: 'Quoter', t: Date.now() } }));
}, [base, poll, Q, neventOf(poll.id, poll.pubkey)]);
await page.reload({ waitUntil: 'domcontentloaded' });
await waitText('receive', 20000);
- await page.evaluate(() => document.querySelector('.app-bottom-nav .app-nav-button').click());
+ await page.evaluate(() => [...document.querySelectorAll('.app-nav-button')].find((b) => b.getAttribute('aria-label') === 'Feed').click());
await waitFor(() => document.querySelectorAll('.notes-feed .poll').length >= 2, 20000);
const feedPoll = await page.evaluate(() => {