mirror of
https://github.com/AppFlowy-IO/AppFlowy-Web.git
synced 2025-11-30 19:37:55 +08:00
chore: fix chat model select and add test
This commit is contained in:
205
cypress/e2e/chat/model-selection-persistence.cy.ts
Normal file
205
cypress/e2e/chat/model-selection-persistence.cy.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { AuthTestUtils } from '../../support/auth-utils';
|
||||
import { TestTool } from '../../support/page-utils';
|
||||
import { PageSelectors, SidebarSelectors, ModelSelectorSelectors } from '../../support/selectors';
|
||||
|
||||
describe('Chat Model Selection Persistence Tests', () => {
|
||||
const APPFLOWY_BASE_URL = Cypress.env('APPFLOWY_BASE_URL');
|
||||
const APPFLOWY_GOTRUE_BASE_URL = Cypress.env('APPFLOWY_GOTRUE_BASE_URL');
|
||||
const generateRandomEmail = () => `${uuidv4()}@appflowy.io`;
|
||||
let testEmail: string;
|
||||
|
||||
before(() => {
|
||||
// Log environment configuration for debugging
|
||||
cy.task('log', `Test Environment Configuration:
|
||||
- APPFLOWY_BASE_URL: ${APPFLOWY_BASE_URL}
|
||||
- APPFLOWY_GOTRUE_BASE_URL: ${APPFLOWY_GOTRUE_BASE_URL}`);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Generate unique test data for each test
|
||||
testEmail = generateRandomEmail();
|
||||
});
|
||||
|
||||
describe('Model Selection Persistence', () => {
|
||||
it('should persist selected model after page reload', () => {
|
||||
// Handle uncaught exceptions during workspace creation
|
||||
cy.on('uncaught:exception', (err: Error) => {
|
||||
if (err.message.includes('No workspace or service found')) {
|
||||
return false;
|
||||
}
|
||||
if (err.message.includes('View not found')) {
|
||||
return false;
|
||||
}
|
||||
if (err.message.includes('WebSocket') || err.message.includes('connection')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Step 1: Login
|
||||
cy.task('log', '=== Step 1: Login ===');
|
||||
cy.visit('/login', { failOnStatusCode: false });
|
||||
cy.wait(2000);
|
||||
|
||||
const authUtils = new AuthTestUtils();
|
||||
authUtils.signInWithTestUrl(testEmail).then(() => {
|
||||
cy.url().should('include', '/app');
|
||||
|
||||
// Wait for the app to fully load
|
||||
cy.task('log', 'Waiting for app to fully load...');
|
||||
|
||||
// Wait for the loading screen to disappear and main app to appear
|
||||
cy.get('body', { timeout: 30000 }).should('not.contain', 'Welcome!');
|
||||
|
||||
// Wait for the sidebar to be visible (indicates app is loaded)
|
||||
SidebarSelectors.pageHeader().should('be.visible', { timeout: 30000 });
|
||||
|
||||
// Wait for at least one page to exist in the sidebar
|
||||
PageSelectors.names().should('exist', { timeout: 30000 });
|
||||
|
||||
// Additional wait for stability
|
||||
cy.wait(2000);
|
||||
|
||||
// Step 2: Create an AI Chat
|
||||
cy.task('log', '=== Step 2: Creating AI Chat ===');
|
||||
|
||||
// Expand the first space to see its pages
|
||||
TestTool.expandSpace();
|
||||
cy.wait(1000);
|
||||
|
||||
// Find the first page item and hover over it to show actions
|
||||
PageSelectors.items().first().then($page => {
|
||||
cy.task('log', 'Hovering over first page to show action buttons...');
|
||||
|
||||
// Hover over the page to reveal the action buttons
|
||||
cy.wrap($page)
|
||||
.trigger('mouseenter', { force: true })
|
||||
.trigger('mouseover', { force: true });
|
||||
|
||||
cy.wait(1000);
|
||||
|
||||
// Click the inline add button (plus icon)
|
||||
cy.wrap($page).within(() => {
|
||||
cy.get('[data-testid="inline-add-page"]')
|
||||
.first()
|
||||
.should('be.visible')
|
||||
.click({ force: true });
|
||||
});
|
||||
});
|
||||
|
||||
// Wait for the dropdown menu to appear
|
||||
cy.wait(1000);
|
||||
|
||||
// Click on the AI Chat option from the dropdown
|
||||
cy.get('[data-testid="add-ai-chat-button"]')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
|
||||
cy.task('log', 'Created AI Chat');
|
||||
|
||||
// Wait for navigation to the AI chat page
|
||||
cy.wait(3000);
|
||||
|
||||
// Step 3: Open model selector and select a model
|
||||
cy.task('log', '=== Step 3: Selecting a Model ===');
|
||||
|
||||
// Wait for the chat interface to load
|
||||
cy.wait(2000);
|
||||
|
||||
// Click on the model selector button
|
||||
ModelSelectorSelectors.button()
|
||||
.should('be.visible', { timeout: 10000 })
|
||||
.click();
|
||||
|
||||
cy.task('log', 'Opened model selector dropdown');
|
||||
|
||||
// Wait for the dropdown to appear and models to load
|
||||
cy.wait(2000);
|
||||
|
||||
// Select a specific model (we'll select the first non-Auto model if available)
|
||||
ModelSelectorSelectors.options()
|
||||
.then($options => {
|
||||
// Find a model that's not "Auto"
|
||||
const nonAutoOptions = $options.filter((i, el) => {
|
||||
const testId = el.getAttribute('data-testid');
|
||||
return testId && !testId.includes('model-option-Auto');
|
||||
});
|
||||
|
||||
if (nonAutoOptions.length > 0) {
|
||||
// Click the first non-Auto model
|
||||
const selectedModel = nonAutoOptions[0].getAttribute('data-testid')?.replace('model-option-', '');
|
||||
cy.task('log', `Selecting model: ${selectedModel}`);
|
||||
cy.wrap(nonAutoOptions[0]).click();
|
||||
|
||||
// Store the selected model name for verification
|
||||
cy.wrap(selectedModel).as('selectedModel');
|
||||
} else {
|
||||
// If only Auto is available, select it explicitly
|
||||
cy.task('log', 'Only Auto model available, selecting it');
|
||||
ModelSelectorSelectors.optionByName('Auto').click();
|
||||
cy.wrap('Auto').as('selectedModel');
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for the selection to be applied
|
||||
cy.wait(1000);
|
||||
|
||||
// Verify the model is selected by checking the button text
|
||||
cy.get('@selectedModel').then((modelName) => {
|
||||
cy.task('log', `Verifying model ${modelName} is displayed in button`);
|
||||
ModelSelectorSelectors.button()
|
||||
.should('contain.text', modelName);
|
||||
});
|
||||
|
||||
// Step 4: Save the current URL for reload
|
||||
cy.task('log', '=== Step 4: Saving current URL ===');
|
||||
cy.url().then(url => {
|
||||
cy.wrap(url).as('chatUrl');
|
||||
cy.task('log', `Current chat URL: ${url}`);
|
||||
});
|
||||
|
||||
// Step 5: Reload the page
|
||||
cy.task('log', '=== Step 5: Reloading page ===');
|
||||
cy.reload();
|
||||
|
||||
// Wait for the page to reload completely
|
||||
cy.wait(3000);
|
||||
|
||||
// Step 6: Verify the model selection persisted
|
||||
cy.task('log', '=== Step 6: Verifying Model Selection Persisted ===');
|
||||
|
||||
// Wait for the model selector button to be visible again
|
||||
ModelSelectorSelectors.button()
|
||||
.should('be.visible', { timeout: 10000 });
|
||||
|
||||
// Verify the previously selected model is still displayed
|
||||
cy.get('@selectedModel').then((modelName) => {
|
||||
cy.task('log', `Checking if model ${modelName} is still selected after reload`);
|
||||
ModelSelectorSelectors.button()
|
||||
.should('contain.text', modelName);
|
||||
cy.task('log', `✓ Model ${modelName} persisted after page reload!`);
|
||||
});
|
||||
|
||||
// Optional: Open the dropdown again to verify the selection visually
|
||||
cy.task('log', '=== Step 7: Double-checking selection in dropdown ===');
|
||||
ModelSelectorSelectors.button().click();
|
||||
cy.wait(1000);
|
||||
|
||||
// Verify the selected model has the selected styling
|
||||
cy.get('@selectedModel').then((modelName) => {
|
||||
ModelSelectorSelectors.optionByName(modelName as string)
|
||||
.should('have.class', 'bg-fill-content-select');
|
||||
cy.task('log', `✓ Model ${modelName} shows as selected in dropdown`);
|
||||
});
|
||||
|
||||
// Close the dropdown
|
||||
cy.get('body').click(0, 0);
|
||||
|
||||
// Final verification
|
||||
cy.task('log', '=== Test completed successfully! ===');
|
||||
cy.task('log', '✓✓✓ Model selection persisted after page reload');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -184,6 +184,27 @@ export const SidebarSelectors = {
|
||||
pageHeader: () => cy.get(byTestId('sidebar-page-header')),
|
||||
};
|
||||
|
||||
/**
|
||||
* Chat Model Selector-related selectors
|
||||
* Used for testing AI model selection in chat interface
|
||||
*/
|
||||
export const ModelSelectorSelectors = {
|
||||
// Model selector button
|
||||
button: () => cy.get(byTestId('model-selector-button')),
|
||||
|
||||
// Model search input
|
||||
searchInput: () => cy.get(byTestId('model-search-input')),
|
||||
|
||||
// Get all model options
|
||||
options: () => cy.get('[data-testid^="model-option-"]'),
|
||||
|
||||
// Get specific model option by name
|
||||
optionByName: (modelName: string) => cy.get(byTestId(`model-option-${modelName}`)),
|
||||
|
||||
// Get selected model option (has the selected class)
|
||||
selectedOption: () => cy.get('[data-testid^="model-option-"]').filter('.bg-fill-content-select'),
|
||||
};
|
||||
|
||||
/**
|
||||
* Database Grid-related selectors
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user