- Increase logo size (48x48 desktop, 56x56 mobile) for better visibility - Add logo as favicon - Add logo to mobile header - Move user menu to navigation bars (sidebar on desktop, bottom bar on mobile) - Fix desktop chat layout - container structure prevents voice controls cutoff - Fix mobile bottom bar - use icon-only ActionIcons instead of truncated text buttons - Hide Create Node/New Conversation buttons on mobile to save header space - Make fixed header and voice controls work properly with containers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
221 lines
7.8 KiB
TypeScript
221 lines
7.8 KiB
TypeScript
/**
|
|
* Magnitude Tests: Node Publishing Flow
|
|
*
|
|
* Tests for the complete node creation, editing, and publishing workflow.
|
|
* Covers both happy path and error scenarios.
|
|
*/
|
|
|
|
import { test } from 'magnitude-test';
|
|
|
|
// ============================================================================
|
|
// HAPPY PATH TESTS
|
|
// ============================================================================
|
|
|
|
test('User can publish a node from conversation', async (agent) => {
|
|
await agent.open('http://localhost:3000');
|
|
|
|
// Step 1: Login with Bluesky
|
|
await agent.act('Click the "Log in with Bluesky" button');
|
|
await agent.check('Redirected to Bluesky login page');
|
|
|
|
await agent.act('Fill in username and password')
|
|
.data({
|
|
username: process.env.TEST_BLUESKY_USERNAME || 'test-user.bsky.social',
|
|
password: process.env.TEST_BLUESKY_PASSWORD || 'test-password',
|
|
});
|
|
|
|
await agent.act('Click the login submit button');
|
|
await agent.check('Redirected back to app and logged in');
|
|
await agent.check('Chat interface is visible');
|
|
|
|
// Step 2: Start a conversation
|
|
await agent.act('Type "Let\'s discuss the philosophy of decentralized social networks" into the chat input and press Enter');
|
|
await agent.check('Message appears in chat');
|
|
await agent.check('AI response appears');
|
|
|
|
// Step 3: Create node draft
|
|
await agent.act('Click the "Create Node" button');
|
|
await agent.check('Navigated to edit page');
|
|
await agent.check('Title input has AI-generated content');
|
|
await agent.check('Content textarea has AI-generated content');
|
|
await agent.check('Conversation context is visible at the bottom');
|
|
|
|
// Step 4: Publish the node
|
|
await agent.act('Click the "Publish Node" button');
|
|
await agent.check('Success notification appears with "Node published!"');
|
|
await agent.check('Returned to conversation view');
|
|
});
|
|
|
|
test('User can edit node draft before publishing', async (agent) => {
|
|
// Assumes user is already logged in from previous test
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
// Start conversation
|
|
await agent.act('Type "Testing the edit flow" and press Enter');
|
|
await agent.check('AI responds');
|
|
|
|
// Create draft
|
|
await agent.act('Click "Create Node"');
|
|
await agent.check('On edit page with draft content');
|
|
|
|
// Edit the content
|
|
await agent.act('Clear the title input and type "My Custom Title"');
|
|
await agent.act('Modify the content textarea to add "This is my edited content."');
|
|
|
|
await agent.check('Title shows "My Custom Title"');
|
|
await agent.check('Content includes "This is my edited content."');
|
|
|
|
// Publish
|
|
await agent.act('Click "Publish Node"');
|
|
await agent.check('Success notification appears');
|
|
});
|
|
|
|
test('User can cancel node draft without publishing', async (agent) => {
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
// Start conversation
|
|
await agent.act('Type "Test cancellation" and press Enter');
|
|
await agent.check('AI responds');
|
|
|
|
// Create draft
|
|
await agent.act('Click "Create Node"');
|
|
await agent.check('On edit page');
|
|
|
|
// Cancel instead of publishing
|
|
await agent.act('Click the "Cancel" button');
|
|
await agent.check('Returned to conversation view');
|
|
await agent.check('Draft was not published'); // Verify no success notification
|
|
});
|
|
|
|
// ============================================================================
|
|
// UNHAPPY PATH TESTS
|
|
// ============================================================================
|
|
|
|
test('Cannot publish node without authentication', async (agent) => {
|
|
// Open edit page directly without being logged in
|
|
await agent.open('http://localhost:3000/edit');
|
|
|
|
await agent.check('Shows empty state message');
|
|
await agent.check('Message says "No Node Draft"');
|
|
await agent.check('Suggests to start a conversation');
|
|
});
|
|
|
|
test('Cannot publish node with empty title', async (agent) => {
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
// Create draft
|
|
await agent.act('Type "Test empty title validation" and press Enter');
|
|
await agent.check('AI responds');
|
|
await agent.act('Click "Create Node"');
|
|
await agent.check('On edit page');
|
|
|
|
// Clear the title
|
|
await agent.act('Clear the title input completely');
|
|
|
|
await agent.check('Publish button is disabled');
|
|
});
|
|
|
|
test('Cannot publish node with empty content', async (agent) => {
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
// Create draft
|
|
await agent.act('Type "Test empty content validation" and press Enter');
|
|
await agent.check('AI responds');
|
|
await agent.act('Click "Create Node"');
|
|
await agent.check('On edit page');
|
|
|
|
// Clear the content
|
|
await agent.act('Clear the content textarea completely');
|
|
|
|
await agent.check('Publish button is disabled');
|
|
});
|
|
|
|
test('Shows error notification if publish fails', async (agent) => {
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
// Create draft
|
|
await agent.act('Type "Test error handling" and press Enter');
|
|
await agent.check('AI responds');
|
|
await agent.act('Click "Create Node"');
|
|
await agent.check('On edit page');
|
|
|
|
// Simulate network failure by disconnecting (this is a mock scenario)
|
|
// In real test, this would require mocking the API
|
|
await agent.act('Click "Publish Node"');
|
|
|
|
// If there's a network error, should see error notification
|
|
// Note: This test may need to mock the fetch call to force an error
|
|
await agent.check('Either success or error notification appears');
|
|
});
|
|
|
|
test('Handles long content with truncation', async (agent) => {
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
// Create a very long message
|
|
const longMessage = 'A'.repeat(500) + ' This is a test of long content truncation for Bluesky posts.';
|
|
|
|
await agent.act(`Type "${longMessage}" and press Enter`);
|
|
await agent.check('AI responds');
|
|
|
|
await agent.act('Click "Create Node"');
|
|
await agent.check('On edit page');
|
|
|
|
await agent.act('Click "Publish Node"');
|
|
|
|
// Should still publish successfully (with truncation)
|
|
await agent.check('Success notification appears');
|
|
await agent.check('May show warning about cache or truncation');
|
|
});
|
|
|
|
test('Shows warning when cache fails but publish succeeds', async (agent) => {
|
|
await agent.open('http://localhost:3000/chat');
|
|
|
|
await agent.act('Type "Test cache failure graceful degradation" and press Enter');
|
|
await agent.check('AI responds');
|
|
|
|
await agent.act('Click "Create Node"');
|
|
await agent.check('On edit page');
|
|
|
|
await agent.act('Click "Publish Node"');
|
|
|
|
// The system should succeed even if cache/embeddings fail
|
|
await agent.check('Success notification appears');
|
|
// May show yellow warning notification instead of green success
|
|
await agent.check('Notification says "Node published"');
|
|
});
|
|
|
|
// ============================================================================
|
|
// INTEGRATION TESTS
|
|
// ============================================================================
|
|
|
|
test('Complete user journey: Login → Converse → Publish → View', async (agent) => {
|
|
// Full end-to-end test
|
|
await agent.open('http://localhost:3000');
|
|
|
|
// Login
|
|
await agent.act('Login with Bluesky')
|
|
.data({
|
|
username: process.env.TEST_BLUESKY_USERNAME,
|
|
password: process.env.TEST_BLUESKY_PASSWORD,
|
|
});
|
|
await agent.check('Logged in successfully');
|
|
|
|
// Have a meaningful conversation
|
|
await agent.act('Type "I want to explore the concept of digital gardens" and send');
|
|
await agent.check('AI responds with insights');
|
|
|
|
await agent.act('Reply with "How do digital gardens differ from blogs?"');
|
|
await agent.check('AI provides detailed explanation');
|
|
|
|
// Create and publish
|
|
await agent.act('Click "Create Node"');
|
|
await agent.check('Draft generated from conversation');
|
|
|
|
await agent.act('Review the draft and click "Publish Node"');
|
|
await agent.check('Node published successfully');
|
|
|
|
// Verify we can continue the conversation
|
|
await agent.check('Back in conversation view');
|
|
await agent.check('Can type new messages');
|
|
});
|