Files
q-blog/tests/pages/CreatePost.publish.new.test.tsx
2025-09-16 14:05:34 -04:00

140 lines
4.7 KiB
TypeScript

import React from 'react';
import { describe, it, expect, vi } from 'vitest';
import { configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import { CreatePost } from '@/pages/CreatePost/CreatePost';
import notificationsReducer from '@/state/features/notificationsSlice';
import authReducer, { addUser } from '@/state/features/authSlice';
import globalReducer, { setCurrentBlog } from '@/state/features/globalSlice';
import blogReducer from '@/state/features/blogSlice';
import mailReducer from '@/state/features/mailSlice';
import bookmarksReducer from '@/state/features/bookmarksSlice';
import { server } from '../msw/server';
const createTestStore = () =>
configureStore({
reducer: {
notifications: notificationsReducer,
auth: authReducer,
global: globalReducer,
blog: blogReducer,
mail: mailReducer,
bookmarks: bookmarksReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
type TestStore = ReturnType<typeof createTestStore>;
const renderCreatePost = (store: TestStore) =>
render(
<Provider store={store}>
<ThemeProvider theme={createTheme()}>
<MemoryRouter initialEntries={[`/post/new`]}>
<Routes>
<Route path="/post/new" element={<CreatePost />} />
</Routes>
</MemoryRouter>
</ThemeProvider>
</Provider>,
);
const selectMinimalEditor = async () => {
const user = userEvent.setup();
const option = await screen.findByText('Minimal Editor');
await user.click(option);
await screen.findByPlaceholderText('Title');
return user;
};
describe('CreatePost (new publish flow)', () => {
const categoriesHandler = http.get('/arbitrary/categories', () => HttpResponse.json([]));
it('surfaces an error when no blog is selected', async () => {
server.use(categoriesHandler);
const store = createTestStore();
globalThis.qortalRequest = vi.fn().mockResolvedValue({ ok: true });
store.dispatch(addUser({ address: 'QADDR', publicKey: 'PUB', name: 'alice' }));
renderCreatePost(store);
const user = await selectMinimalEditor();
const titleField = await screen.findByPlaceholderText('Title');
await user.type(titleField, 'Unsaved Draft');
const publishTrigger = await screen.findByRole('button', { name: /^Publish$/i });
await user.click(publishTrigger);
const submitButton = await screen.findByRole('button', { name: /Submit/i });
await user.click(submitButton);
await waitFor(() => {
expect(store.getState().notifications.alertTypes.alertError).toBe(
'Cannot determine which blog to publish to. Open your blog and try again.',
);
});
expect(globalThis.qortalRequest).not.toHaveBeenCalled();
}, 10000);
it('publishes a new post when currentBlog is available', async () => {
server.use(categoriesHandler);
const store = createTestStore();
globalThis.qortalRequest = vi.fn().mockResolvedValue({ ok: true });
store.dispatch(addUser({ address: 'QADDR', publicKey: 'PUB', name: 'alice' }));
store.dispatch(
setCurrentBlog({
createdAt: Date.now(),
blogId: 'q-blog-myblog',
title: 'My Blog',
description: '',
blogImage: '',
category: '',
tags: [],
wikiEnabled: false,
editorWhitelist: [],
editorBlacklist: [],
}),
);
renderCreatePost(store);
const user = await selectMinimalEditor();
const titleField = await screen.findByPlaceholderText('Title');
await user.type(titleField, 'My New Post');
const publishTrigger = await screen.findByRole('button', { name: /^Publish$/i });
await user.click(publishTrigger);
const submitButton = await screen.findByRole('button', { name: /Submit/i });
await user.click(submitButton);
await waitFor(() => {
expect(globalThis.qortalRequest).toHaveBeenCalled();
});
const publishCall = (globalThis.qortalRequest as any).mock.calls.find(
(call: any[]) => call[0]?.action === 'PUBLISH_QDN_RESOURCE',
);
expect(publishCall).toBeTruthy();
expect(publishCall?.[0]).toMatchObject({
action: 'PUBLISH_QDN_RESOURCE',
service: 'BLOG_POST',
});
expect(publishCall?.[0]?.identifier.startsWith('q-blog-myblog-post-')).toBe(true);
await waitFor(() => {
expect(store.getState().notifications.alertTypes.alertSuccess).toBe(
'Blog post successfully published',
);
});
}, 10000);
});