forked from Qortal-Forker/q-blog
test: add wiki editor route canonical-load test and feed edit-pencil visibility test; run prettier
All checks were successful
CI / build_test (push) Successful in 3m43s
All checks were successful
CI / build_test (push) Successful in 3m43s
This commit is contained in:
@@ -210,7 +210,9 @@ export const EditPost = () => {
|
||||
const searchUrl = `/arbitrary/resources/search?mode=ALL&service=BLOG_POST&identifier=${encodeURIComponent(
|
||||
fullId,
|
||||
)}&limit=50&includemetadata=true&reverse=true&excludeblocked=true`;
|
||||
const searchResp = await fetch(searchUrl, { headers: { 'Content-Type': 'application/json' } });
|
||||
const searchResp = await fetch(searchUrl, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
const items = (await searchResp.json()) || [];
|
||||
const revisions = items.map((it: any) => ({
|
||||
id: it.identifier,
|
||||
|
||||
@@ -89,7 +89,12 @@ export const UserBlogs: React.FC = () => {
|
||||
<>
|
||||
{isOwner && (
|
||||
<Box sx={{ textAlign: 'right', mb: 1 }}>
|
||||
<Button variant="contained" color="primary" onClick={onCreate} aria-label="Create Blog">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={onCreate}
|
||||
aria-label="Create Blog"
|
||||
>
|
||||
Create Blog
|
||||
</Button>
|
||||
</Box>
|
||||
@@ -100,11 +105,23 @@ export const UserBlogs: React.FC = () => {
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<Button size="small" color="primary" variant="outlined" onClick={() => onView(b)} aria-label={`View blog ${b.title || b.handle}`}>
|
||||
<Button
|
||||
size="small"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
onClick={() => onView(b)}
|
||||
aria-label={`View blog ${b.title || b.handle}`}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
{isOwner && (
|
||||
<Button size="small" color="primary" variant="contained" onClick={() => onEdit(b)} aria-label={`Edit blog ${b.title || b.handle}`}>
|
||||
<Button
|
||||
size="small"
|
||||
color="primary"
|
||||
variant="contained"
|
||||
onClick={() => onEdit(b)}
|
||||
aria-label={`Edit blog ${b.title || b.handle}`}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
)}
|
||||
|
||||
67
tests/pages/BlogList.wiki-edit.test.tsx
Normal file
67
tests/pages/BlogList.wiki-edit.test.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React from 'react';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from '@/state/store';
|
||||
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { server } from '../msw/server';
|
||||
import { BlogList } from '@/pages/BlogList/BlogList';
|
||||
import { addPosts } from '@/state/features/blogSlice';
|
||||
import { addUser } from '@/state/features/authSlice';
|
||||
|
||||
describe('BlogList — wiki edit pencil visibility', () => {
|
||||
it('shows edit pencil for authorized non-owner editor', async () => {
|
||||
// Configure auth user as bob
|
||||
store.dispatch(addUser({ address: 'A', publicKey: 'P', name: 'bob' }));
|
||||
// Seed one post from another user
|
||||
store.dispatch(
|
||||
addPosts([
|
||||
{
|
||||
id: 'q-blog-myblog-post-123',
|
||||
user: 'carol',
|
||||
title: 'T',
|
||||
description: 'd',
|
||||
createdAt: 1,
|
||||
} as any,
|
||||
]),
|
||||
);
|
||||
|
||||
// Owner + settings (whitelist bob)
|
||||
server.use(
|
||||
http.get('/arbitrary/resources', ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
if (
|
||||
url.searchParams.get('service') === 'BLOG' &&
|
||||
url.searchParams.get('identifier') === 'q-blog-myblog'
|
||||
) {
|
||||
return HttpResponse.json([{ name: 'alice', identifier: 'q-blog-myblog' }]);
|
||||
}
|
||||
return HttpResponse.json([]);
|
||||
}),
|
||||
http.get('/arbitrary/BLOG/:name/:id', ({ params }) => {
|
||||
const { name, id } = params as any;
|
||||
if (name === 'alice' && id === 'q-blog-myblog') {
|
||||
return HttpResponse.json({ wikiEnabled: true, editorWhitelist: ['bob'] });
|
||||
}
|
||||
return HttpResponse.json({}, { status: 404 });
|
||||
}),
|
||||
);
|
||||
|
||||
const { container } = render(
|
||||
<Provider store={store}>
|
||||
<ThemeProvider theme={createTheme()}>
|
||||
<MemoryRouter>
|
||||
<BlogList />
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
const pencil = container.querySelector('.edit-btn');
|
||||
expect(pencil).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
77
tests/pages/EditPost.wiki.test.tsx
Normal file
77
tests/pages/EditPost.wiki.test.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from '@/state/store';
|
||||
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import { server } from '../msw/server';
|
||||
import { EditPost } from '@/pages/EditPost/EditPost';
|
||||
|
||||
describe('EditPost — wiki canonical loading', () => {
|
||||
it('loads canonical content by identifier across names', async () => {
|
||||
// BLOG owner + settings
|
||||
server.use(
|
||||
http.get('/arbitrary/resources', ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
if (
|
||||
url.searchParams.get('service') === 'BLOG' &&
|
||||
url.searchParams.get('identifier') === 'q-blog-myblog'
|
||||
) {
|
||||
return HttpResponse.json([{ name: 'alice', identifier: 'q-blog-myblog' }]);
|
||||
}
|
||||
return HttpResponse.json([]);
|
||||
}),
|
||||
http.get('/arbitrary/BLOG/:name/:id', ({ params }) => {
|
||||
const { name, id } = params as any;
|
||||
if (name === 'alice' && id === 'q-blog-myblog') {
|
||||
return HttpResponse.json({ wikiEnabled: true });
|
||||
}
|
||||
return HttpResponse.json({}, { status: 404 });
|
||||
}),
|
||||
// Search across names by full identifier
|
||||
http.get('/arbitrary/resources/search', ({ request }) => {
|
||||
const url = new URL(request.url);
|
||||
if (
|
||||
url.searchParams.get('service') === 'BLOG_POST' &&
|
||||
url.searchParams.get('identifier') === 'q-blog-myblog-post-123'
|
||||
) {
|
||||
return HttpResponse.json([
|
||||
{ name: 'alice', identifier: 'q-blog-myblog-post-123', updated: 1000 },
|
||||
{ name: 'carol', identifier: 'q-blog-myblog-post-123', updated: 2000 },
|
||||
]);
|
||||
}
|
||||
return HttpResponse.json([]);
|
||||
}),
|
||||
// Canonical chosen should be carol (newer)
|
||||
http.get('/arbitrary/BLOG_POST/:name/:fullId', ({ params }) => {
|
||||
const { name, fullId } = params as any;
|
||||
if (name === 'carol' && fullId === 'q-blog-myblog-post-123') {
|
||||
return HttpResponse.json({
|
||||
title: 'Newer Title',
|
||||
createdAt: 1,
|
||||
postContent: [{ type: 'editor', version: 1, id: 'e1', content: [{ text: 'Hello' }] }],
|
||||
});
|
||||
}
|
||||
return HttpResponse.json({}, { status: 404 });
|
||||
}),
|
||||
);
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<ThemeProvider theme={createTheme()}>
|
||||
<MemoryRouter initialEntries={[`/bob/myblog/123/edit`]}>
|
||||
<Routes>
|
||||
<Route path="/:user/:blog/:postId/edit" element={<EditPost />} />
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
</Provider>,
|
||||
);
|
||||
|
||||
// Title input should pick canonical content's title
|
||||
const titleInput = await screen.findByDisplayValue('Newer Title');
|
||||
expect(titleInput).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user