fix: show only fully published events in Most Recent Publication box
- Add PublicationStatus type and computePublicationStatus() helper - Add useProfilePublications hook that queries relays via feedGet and determines per-event publication status by comparing served relays against all enabled relays - Rewrite HomeScreen PublicationResult to show only fully published events in the main box; partial events appear only in the expandable Relay results section - Show empty state when no fully published events exist - Add tests: fully published shown, partial hidden, older full shown when newest is partial, all-partial shows empty, relay details expandable, no duplicates - Fix publishFlow integration test to seed profileFeedItems
This commit is contained in:
parent
9cf4003c31
commit
ea56806c0c
6 changed files with 360 additions and 59 deletions
69
frontend/src/lib/publications.ts
Normal file
69
frontend/src/lib/publications.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import type { FeedItem, PublicationStatus, RelayConfig } from './types';
|
||||||
|
import { useApp } from '../state/AppProvider';
|
||||||
|
|
||||||
|
/** Determine whether a note is fully or partially published. */
|
||||||
|
export function computePublicationStatus(
|
||||||
|
itemRelays: string[],
|
||||||
|
enabledRelays: RelayConfig[],
|
||||||
|
): PublicationStatus {
|
||||||
|
const enabled = enabledRelays.filter((r) => r.enabled).map((r) => r.url);
|
||||||
|
if (enabled.length === 0) {
|
||||||
|
return 'fully_published';
|
||||||
|
}
|
||||||
|
const served = new Set(itemRelays);
|
||||||
|
const allServed = enabled.every((url) => served.has(url));
|
||||||
|
return allServed ? 'fully_published' : 'partially_published';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProfilePublication extends FeedItem {
|
||||||
|
publicationStatus: PublicationStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UseProfilePublicationsResult {
|
||||||
|
publications: ProfilePublication[];
|
||||||
|
fullyPublished: ProfilePublication[];
|
||||||
|
loading: boolean;
|
||||||
|
error: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useProfilePublications(): UseProfilePublicationsResult {
|
||||||
|
const { state, feedGet } = useApp();
|
||||||
|
const [publications, setPublications] = useState<ProfilePublication[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const authorNpub = state?.active_profile?.npub ?? null;
|
||||||
|
|
||||||
|
const load = useCallback(async () => {
|
||||||
|
if (!authorNpub) {
|
||||||
|
setPublications([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
try {
|
||||||
|
const items = await feedGet(50, false, authorNpub);
|
||||||
|
const enabledRelays = state?.settings.relays ?? [];
|
||||||
|
const enriched: ProfilePublication[] = items.map((item) => ({
|
||||||
|
...item,
|
||||||
|
publicationStatus: computePublicationStatus(item.relays, enabledRelays),
|
||||||
|
}));
|
||||||
|
enriched.sort((a, b) => b.created_at - a.created_at);
|
||||||
|
setPublications(enriched);
|
||||||
|
} catch (err) {
|
||||||
|
setError(err instanceof Error ? err.message : String(err));
|
||||||
|
setPublications([]);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [authorNpub, feedGet, state?.settings.relays]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
void load();
|
||||||
|
}, [load]);
|
||||||
|
|
||||||
|
const fullyPublished = publications.filter((p) => p.publicationStatus === 'fully_published');
|
||||||
|
|
||||||
|
return { publications, fullyPublished, loading, error };
|
||||||
|
}
|
||||||
|
|
@ -76,6 +76,9 @@ export interface MetadataPublishReport {
|
||||||
failed: RelayFailure[];
|
failed: RelayFailure[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Publication status derived from comparing served relays against all enabled relays. */
|
||||||
|
export type PublicationStatus = 'fully_published' | 'partially_published';
|
||||||
|
|
||||||
/** A single note shown in the aggregated feed. */
|
/** A single note shown in the aggregated feed. */
|
||||||
export interface FeedItem {
|
export interface FeedItem {
|
||||||
/** Bech32 note id. */
|
/** Bech32 note id. */
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import { EmptyState } from '../components/EmptyState';
|
||||||
import { Icon } from '../components/Icon';
|
import { Icon } from '../components/Icon';
|
||||||
import { shortenNpub } from '../lib/format';
|
import { shortenNpub } from '../lib/format';
|
||||||
import type { Screen } from '../lib/navigation';
|
import type { Screen } from '../lib/navigation';
|
||||||
|
import type { ProfilePublication } from '../lib/publications';
|
||||||
|
import { useProfilePublications } from '../lib/publications';
|
||||||
import { useApp } from '../state/AppProvider';
|
import { useApp } from '../state/AppProvider';
|
||||||
|
|
||||||
interface HomeScreenProps {
|
interface HomeScreenProps {
|
||||||
|
|
@ -16,7 +18,8 @@ interface HomeScreenProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HomeScreen({ onNavigate, onCreateProfile }: HomeScreenProps) {
|
export function HomeScreen({ onNavigate, onCreateProfile }: HomeScreenProps) {
|
||||||
const { state, lastPublish, selectProfile } = useApp();
|
const { state, selectProfile } = useApp();
|
||||||
|
const { publications, fullyPublished, loading, error } = useProfilePublications();
|
||||||
const [selecting, setSelecting] = useState<string | null>(null);
|
const [selecting, setSelecting] = useState<string | null>(null);
|
||||||
|
|
||||||
const onSelect = async (npub: string) => {
|
const onSelect = async (npub: string) => {
|
||||||
|
|
@ -182,7 +185,10 @@ export function HomeScreen({ onNavigate, onCreateProfile }: HomeScreenProps) {
|
||||||
</header>
|
</header>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<PublicationResult
|
<PublicationResult
|
||||||
lastPublish={lastPublish}
|
publications={publications}
|
||||||
|
fullyPublished={fullyPublished}
|
||||||
|
loading={loading}
|
||||||
|
error={error}
|
||||||
onNavigateCompose={() => onNavigate('compose')}
|
onNavigateCompose={() => onNavigate('compose')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -193,18 +199,34 @@ export function HomeScreen({ onNavigate, onCreateProfile }: HomeScreenProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function PublicationResult({
|
function PublicationResult({
|
||||||
lastPublish,
|
publications,
|
||||||
|
fullyPublished,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
onNavigateCompose,
|
onNavigateCompose,
|
||||||
}: {
|
}: {
|
||||||
lastPublish: ReturnType<typeof useApp>['lastPublish'];
|
publications: ProfilePublication[];
|
||||||
|
fullyPublished: ProfilePublication[];
|
||||||
|
loading: boolean;
|
||||||
|
error: string | null;
|
||||||
onNavigateCompose: () => void;
|
onNavigateCompose: () => void;
|
||||||
}) {
|
}) {
|
||||||
if (!lastPublish) {
|
if (loading) {
|
||||||
|
return <p className="muted">Loading publications…</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<Alert tone="error" title="Could not load publications">
|
||||||
|
{error}
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publications.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="home-publish-empty">
|
<div className="home-publish-empty">
|
||||||
<p className="muted">
|
<p className="muted">You haven't published anything yet.</p>
|
||||||
You haven't published anything yet.
|
|
||||||
</p>
|
|
||||||
<Button variant="secondary" size="sm" onClick={onNavigateCompose}>
|
<Button variant="secondary" size="sm" onClick={onNavigateCompose}>
|
||||||
<Icon name="edit" size={16} />
|
<Icon name="edit" size={16} />
|
||||||
Compose your first note
|
Compose your first note
|
||||||
|
|
@ -213,63 +235,60 @@ function PublicationResult({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastPublish.error) {
|
const newest = fullyPublished[0] ?? null;
|
||||||
|
const newestPartial =
|
||||||
|
publications.find((p) => p.publicationStatus === 'partially_published') ?? null;
|
||||||
|
|
||||||
|
if (!newest && !newestPartial) {
|
||||||
return (
|
return (
|
||||||
<Alert tone="error" title="Publication failed" details={lastPublish.details}>
|
<div className="home-publish-empty">
|
||||||
{lastPublish.error}
|
<p className="muted">No fully published publications found.</p>
|
||||||
</Alert>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const report = lastPublish.report;
|
if (!newest) {
|
||||||
if (!report) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (report.failed.length === 0) {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="home-publish-empty">
|
||||||
<div className="publish-result success">
|
<p className="muted">No fully published publications found.</p>
|
||||||
<Badge tone="success">
|
{newestPartial && <PartialPublicationDetails item={newestPartial} />}
|
||||||
<Icon name="check" size={14} /> Published
|
</div>
|
||||||
</Badge>
|
|
||||||
<span className="mono" title={report.event_id}>
|
|
||||||
{shortenNpub(report.event_id, true)}
|
|
||||||
</span>
|
|
||||||
<CopyButton text={report.event_id} label="event ID" />
|
|
||||||
</div>
|
|
||||||
{report.content && <p className="publish-preview">{report.content}</p>}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="publish-result">
|
<>
|
||||||
<Alert tone="warning" title="Partially published">
|
<div className="publish-result success">
|
||||||
The note reached {report.succeeded.length} of{' '}
|
<Badge tone="success">
|
||||||
{report.succeeded.length + report.failed.length} enabled relays. Event ID:{' '}
|
<Icon name="check" size={14} /> Published
|
||||||
<code className="mono" title={report.event_id}>
|
</Badge>
|
||||||
{shortenNpub(report.event_id, true)}
|
<span className="mono" title={newest.id}>
|
||||||
</code>
|
{shortenNpub(newest.id, true)}
|
||||||
</Alert>
|
</span>
|
||||||
<CopyButton text={report.event_id} label="event ID" />
|
<CopyButton text={newest.id} label="event ID" />
|
||||||
{report.content && <p className="publish-preview">{report.content}</p>}
|
</div>
|
||||||
<details className="alert-details">
|
{newest.content && <p className="publish-preview">{newest.content}</p>}
|
||||||
<summary>Relay results</summary>
|
{newestPartial && newestPartial.id !== newest.id && (
|
||||||
<ul className="relay-result-list">
|
<PartialPublicationDetails item={newestPartial} />
|
||||||
{report.succeeded.map((url) => (
|
)}
|
||||||
<li key={url} className="ok">
|
</>
|
||||||
<span className="mono">{url}</span> — accepted
|
);
|
||||||
</li>
|
}
|
||||||
))}
|
|
||||||
{report.failed.map((failure) => (
|
function PartialPublicationDetails({ item }: { item: ProfilePublication }) {
|
||||||
<li key={failure.url} className="bad">
|
const totalRelays = item.relays.length;
|
||||||
<span className="mono">{failure.url}</span> — {failure.error}
|
return (
|
||||||
</li>
|
<details className="alert-details">
|
||||||
))}
|
<summary>Relay results</summary>
|
||||||
</ul>
|
<ul className="relay-result-list">
|
||||||
</details>
|
{item.relays.map((url) => (
|
||||||
</div>
|
<li key={url} className="ok">
|
||||||
|
<span className="mono">{url}</span> — accepted
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
{totalRelays === 0 && <li className="bad">No relays returned this event.</li>}
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,12 @@ export function AppProvider({ children }: { children: ReactNode }) {
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
setState(initial);
|
setState(initial);
|
||||||
if (initial.last_publish) {
|
if (initial.last_publish) {
|
||||||
setLastPublish({ report: initial.last_publish, error: null, details: null, at: Date.now() });
|
setLastPublish({
|
||||||
|
report: initial.last_publish,
|
||||||
|
error: null,
|
||||||
|
details: null,
|
||||||
|
at: Date.now(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
194
frontend/src/test/publications.test.tsx
Normal file
194
frontend/src/test/publications.test.tsx
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
import { screen, waitFor } from '@testing-library/react';
|
||||||
|
import { HomeScreen } from '../screens/HomeScreen';
|
||||||
|
import { renderWithApp } from './render';
|
||||||
|
import { ALICE } from './apiMock';
|
||||||
|
import { createFakeBackend, installFakeBackend } from './fakeBackend';
|
||||||
|
import { computePublicationStatus } from '../lib/publications';
|
||||||
|
import type { FeedItem, RelayConfig } from '../lib/types';
|
||||||
|
|
||||||
|
const RELAYS: RelayConfig[] = [
|
||||||
|
{ url: 'wss://relay.damus.io', enabled: true },
|
||||||
|
{ url: 'wss://relay.nostr.band', enabled: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
function makeItem(overrides: Partial<FeedItem> & { id: string; relays: string[] }): FeedItem {
|
||||||
|
return {
|
||||||
|
author: '7f8b9a0c1d2e3f405162738495a6b7c8d9e0f1a2b3c4d5e6f708192a3b4c5d6e7f',
|
||||||
|
author_npub: ALICE,
|
||||||
|
content: '',
|
||||||
|
created_at: 1700000000,
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderHome(backend: ReturnType<typeof createFakeBackend>) {
|
||||||
|
installFakeBackend(backend);
|
||||||
|
renderWithApp(<HomeScreen onNavigate={vi.fn()} onCreateProfile={vi.fn()} />);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitForData() {
|
||||||
|
await waitFor(() => {
|
||||||
|
const loading = screen.queryByText(/Loading publications/);
|
||||||
|
expect(loading).not.toBeInTheDocument();
|
||||||
|
const emptyNoPub = screen.queryByText("You haven't published anything yet.");
|
||||||
|
expect(emptyNoPub).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('computePublicationStatus', () => {
|
||||||
|
it('returns fully_published when all enabled relays served the event', () => {
|
||||||
|
const item = makeItem({ id: 'a', relays: ['wss://relay.damus.io', 'wss://relay.nostr.band'] });
|
||||||
|
expect(computePublicationStatus(item.relays, RELAYS)).toBe('fully_published');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns partially_published when only some relays served the event', () => {
|
||||||
|
const item = makeItem({ id: 'a', relays: ['wss://relay.damus.io'] });
|
||||||
|
expect(computePublicationStatus(item.relays, RELAYS)).toBe('partially_published');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns fully_published when no relays are configured', () => {
|
||||||
|
expect(computePublicationStatus(['wss://x'], [])).toBe('fully_published');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('HomeScreen — Most recent publication', () => {
|
||||||
|
it('shows the newest fully published event', async () => {
|
||||||
|
const backend = createFakeBackend();
|
||||||
|
backend.profileFeedItems = [
|
||||||
|
makeItem({
|
||||||
|
id: 'note1full',
|
||||||
|
content: 'Fully published note',
|
||||||
|
created_at: 100,
|
||||||
|
relays: ['wss://relay.damus.io', 'wss://relay.nostr.band'],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
renderHome(backend);
|
||||||
|
|
||||||
|
await waitForData();
|
||||||
|
expect(screen.getByText('Fully published note')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/Published/)).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/note1full/)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('hides a partially published newest event from the main box', async () => {
|
||||||
|
const backend = createFakeBackend();
|
||||||
|
backend.profileFeedItems = [
|
||||||
|
makeItem({
|
||||||
|
id: 'note1partial',
|
||||||
|
content: 'Partial note',
|
||||||
|
created_at: 100,
|
||||||
|
relays: ['wss://relay.damus.io'],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
renderHome(backend);
|
||||||
|
|
||||||
|
await waitForData();
|
||||||
|
expect(screen.queryByText('Partial note')).not.toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/No fully published publications found/)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows an older fully published event when the newest is partial', async () => {
|
||||||
|
const backend = createFakeBackend();
|
||||||
|
backend.profileFeedItems = [
|
||||||
|
makeItem({
|
||||||
|
id: 'note1partial',
|
||||||
|
content: 'Newer partial',
|
||||||
|
created_at: 200,
|
||||||
|
relays: ['wss://relay.damus.io'],
|
||||||
|
}),
|
||||||
|
makeItem({
|
||||||
|
id: 'note1full',
|
||||||
|
content: 'Older full',
|
||||||
|
created_at: 100,
|
||||||
|
relays: ['wss://relay.damus.io', 'wss://relay.nostr.band'],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
renderHome(backend);
|
||||||
|
|
||||||
|
await waitForData();
|
||||||
|
expect(screen.getByText('Older full')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/Published/)).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Newer partial')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows empty state when all events are partial', async () => {
|
||||||
|
const backend = createFakeBackend();
|
||||||
|
backend.profileFeedItems = [
|
||||||
|
makeItem({
|
||||||
|
id: 'note1a',
|
||||||
|
content: 'Partial A',
|
||||||
|
created_at: 200,
|
||||||
|
relays: ['wss://relay.damus.io'],
|
||||||
|
}),
|
||||||
|
makeItem({
|
||||||
|
id: 'note1b',
|
||||||
|
content: 'Partial B',
|
||||||
|
created_at: 100,
|
||||||
|
relays: ['wss://relay.nostr.band'],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
renderHome(backend);
|
||||||
|
|
||||||
|
await waitForData();
|
||||||
|
expect(screen.getByText(/No fully published publications found/)).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Partial A')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows partial event details in Relay results expandable', async () => {
|
||||||
|
const backend = createFakeBackend();
|
||||||
|
backend.profileFeedItems = [
|
||||||
|
makeItem({
|
||||||
|
id: 'note1full',
|
||||||
|
content: 'Full note',
|
||||||
|
created_at: 200,
|
||||||
|
relays: ['wss://relay.damus.io', 'wss://relay.nostr.band'],
|
||||||
|
}),
|
||||||
|
makeItem({
|
||||||
|
id: 'note1partial',
|
||||||
|
content: 'Partial note',
|
||||||
|
created_at: 100,
|
||||||
|
relays: ['wss://relay.damus.io'],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
renderHome(backend);
|
||||||
|
|
||||||
|
await waitForData();
|
||||||
|
expect(screen.getByText('Full note')).toBeInTheDocument();
|
||||||
|
|
||||||
|
const relaySummary = screen.getByText('Relay results');
|
||||||
|
expect(relaySummary).toBeInTheDocument();
|
||||||
|
|
||||||
|
const details = relaySummary.closest('details') as HTMLDetailsElement;
|
||||||
|
details.open = true;
|
||||||
|
details.dispatchEvent(new Event('toggle'));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(
|
||||||
|
screen.getByText((_, element) => {
|
||||||
|
return (
|
||||||
|
element?.textContent?.includes('wss://relay.damus.io') === true &&
|
||||||
|
element?.textContent?.includes('accepted') === true &&
|
||||||
|
element?.tagName === 'LI'
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not duplicate events with the same ID', async () => {
|
||||||
|
const backend = createFakeBackend();
|
||||||
|
backend.profileFeedItems = [
|
||||||
|
makeItem({
|
||||||
|
id: 'note1same',
|
||||||
|
content: 'Same event',
|
||||||
|
created_at: 100,
|
||||||
|
relays: ['wss://relay.damus.io', 'wss://relay.nostr.band'],
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
renderHome(backend);
|
||||||
|
|
||||||
|
await waitForData();
|
||||||
|
const matches = screen.getAllByText(/note1same/);
|
||||||
|
expect(matches.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,12 +1,23 @@
|
||||||
import { render, screen, within } from '@testing-library/react';
|
import { render, screen, within } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import App from '../App';
|
import App from '../App';
|
||||||
|
import { ALICE } from './apiMock';
|
||||||
import { createFakeBackend, installFakeBackend } from './fakeBackend';
|
import { createFakeBackend, installFakeBackend } from './fakeBackend';
|
||||||
|
|
||||||
describe('publication flow across screens', () => {
|
describe('publication flow across screens', () => {
|
||||||
it('publishes from Compose and shows the result on Home', async () => {
|
it('publishes from Compose and shows the result on Home', async () => {
|
||||||
const backend = createFakeBackend();
|
const backend = createFakeBackend();
|
||||||
backend.state.settings.confirm_before_publish = false;
|
backend.state.settings.confirm_before_publish = false;
|
||||||
|
backend.profileFeedItems = [
|
||||||
|
{
|
||||||
|
id: backend.publishReport.event_id,
|
||||||
|
author: '7f8b9a0c1d2e3f405162738495a6b7c8d9e0f1a2b3c4d5e6f708192a3b4c5d6e7f',
|
||||||
|
author_npub: ALICE,
|
||||||
|
content: 'Hello from the flow test',
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
relays: ['wss://relay.damus.io', 'wss://relay.nostr.band'],
|
||||||
|
},
|
||||||
|
];
|
||||||
installFakeBackend(backend);
|
installFakeBackend(backend);
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
render(<App />);
|
render(<App />);
|
||||||
|
|
@ -24,7 +35,7 @@ describe('publication flow across screens', () => {
|
||||||
|
|
||||||
await user.click(screen.getByRole('button', { name: 'Home' }));
|
await user.click(screen.getByRole('button', { name: 'Home' }));
|
||||||
await screen.findByRole('heading', { name: 'Home' });
|
await screen.findByRole('heading', { name: 'Home' });
|
||||||
expect(await screen.findByText('Published')).toBeInTheDocument();
|
expect(await screen.findByText(/Published/)).toBeInTheDocument();
|
||||||
expect(screen.getByTitle(backend.publishReport.event_id)).toBeInTheDocument();
|
expect(screen.getByText(/Hello from the flow test/)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue