mirror of
https://github.com/AppFlowy-IO/AppFlowy-Web.git
synced 2025-11-30 11:27:55 +08:00
Merge pull request #66 from AppFlowy-IO/database_test2
chore: switch column type test
This commit is contained in:
@@ -3,6 +3,10 @@ import { AuthTestUtils } from '../../support/auth-utils';
|
|||||||
import {
|
import {
|
||||||
AddPageSelectors,
|
AddPageSelectors,
|
||||||
DatabaseGridSelectors,
|
DatabaseGridSelectors,
|
||||||
|
PropertyMenuSelectors,
|
||||||
|
GridFieldSelectors,
|
||||||
|
SingleSelectSelectors,
|
||||||
|
FieldType,
|
||||||
waitForReactUpdate
|
waitForReactUpdate
|
||||||
} from '../../support/selectors';
|
} from '../../support/selectors';
|
||||||
|
|
||||||
@@ -36,13 +40,47 @@ describe('Single Select Column Type', () => {
|
|||||||
authUtils.signInWithTestUrl(testEmail).then(() => {
|
authUtils.signInWithTestUrl(testEmail).then(() => {
|
||||||
cy.log('[STEP 3] Authentication successful');
|
cy.log('[STEP 3] Authentication successful');
|
||||||
cy.url({ timeout: 30000 }).should('include', '/app');
|
cy.url({ timeout: 30000 }).should('include', '/app');
|
||||||
cy.wait(3000);
|
cy.wait(5000); // Increased wait for CI environment
|
||||||
|
|
||||||
|
// Ensure we're on the right page before proceeding
|
||||||
|
cy.log('[STEP 3.1] Verifying workspace loaded');
|
||||||
|
cy.get('body').should('exist');
|
||||||
|
cy.wait(2000);
|
||||||
|
|
||||||
// Create a new grid
|
// Create a new grid
|
||||||
cy.log('[STEP 4] Creating new grid');
|
cy.log('[STEP 4] Creating new grid');
|
||||||
AddPageSelectors.inlineAddButton().first().click();
|
cy.log('[STEP 4.1] Waiting for inline add button or new page button');
|
||||||
|
|
||||||
|
// Try to find either inline add button or new page button
|
||||||
|
cy.get('body').then($body => {
|
||||||
|
const inlineAddExists = $body.find('[data-testid="inline-add-page"]').length > 0;
|
||||||
|
const newPageExists = $body.find('[data-testid="new-page-button"]').length > 0;
|
||||||
|
|
||||||
|
if (inlineAddExists) {
|
||||||
|
cy.log('[STEP 4.2] Using inline add button');
|
||||||
|
return cy.wrap(null).then(() => {
|
||||||
|
AddPageSelectors.inlineAddButton().first().click({ force: true });
|
||||||
|
});
|
||||||
|
} else if (newPageExists) {
|
||||||
|
cy.log('[STEP 4.2] Using new page button instead');
|
||||||
|
return cy.wrap(null).then(() => {
|
||||||
|
cy.get('[data-testid="new-page-button"]').first().click({ force: true });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Wait a bit more and try inline add button
|
||||||
|
cy.log('[STEP 4.2] Waiting for UI to stabilize');
|
||||||
|
return cy.wrap(null).then(() => {
|
||||||
|
cy.wait(3000);
|
||||||
|
AddPageSelectors.inlineAddButton().should('exist', { timeout: 15000 });
|
||||||
|
AddPageSelectors.inlineAddButton().first().click({ force: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
waitForReactUpdate(1000);
|
waitForReactUpdate(1000);
|
||||||
AddPageSelectors.addGridButton().click();
|
cy.log('[STEP 4.3] Clicking add grid button');
|
||||||
|
AddPageSelectors.addGridButton().should('exist', { timeout: 10000 });
|
||||||
|
AddPageSelectors.addGridButton().click({ force: true });
|
||||||
cy.wait(8000);
|
cy.wait(8000);
|
||||||
|
|
||||||
|
|
||||||
@@ -79,4 +117,215 @@ describe('Single Select Column Type', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should convert SingleSelect to RichText and back preserving options', () => {
|
||||||
|
const testEmail = generateRandomEmail();
|
||||||
|
cy.log(`[TEST START] Testing field type conversion - Test email: ${testEmail}`);
|
||||||
|
|
||||||
|
cy.log('[STEP 1] Visiting login page');
|
||||||
|
cy.visit('/login', { failOnStatusCode: false });
|
||||||
|
cy.wait(2000);
|
||||||
|
|
||||||
|
const authUtils = new AuthTestUtils();
|
||||||
|
cy.log('[STEP 2] Starting authentication');
|
||||||
|
authUtils.signInWithTestUrl(testEmail).then(() => {
|
||||||
|
cy.log('[STEP 3] Authentication successful');
|
||||||
|
cy.url({ timeout: 30000 }).should('include', '/app');
|
||||||
|
cy.wait(5000); // Increased wait for CI environment
|
||||||
|
|
||||||
|
// Ensure we're on the right page before proceeding
|
||||||
|
cy.log('[STEP 3.1] Verifying workspace loaded');
|
||||||
|
cy.get('body').should('exist');
|
||||||
|
cy.wait(2000);
|
||||||
|
|
||||||
|
// Create a new grid
|
||||||
|
cy.log('[STEP 4] Creating new grid');
|
||||||
|
cy.log('[STEP 4.1] Waiting for inline add button');
|
||||||
|
AddPageSelectors.inlineAddButton().should('exist', { timeout: 15000 });
|
||||||
|
AddPageSelectors.inlineAddButton().first().scrollIntoView().click({ force: true });
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
cy.log('[STEP 4.2] Clicking add grid button');
|
||||||
|
AddPageSelectors.addGridButton().should('exist', { timeout: 10000 });
|
||||||
|
AddPageSelectors.addGridButton().click({ force: true });
|
||||||
|
cy.wait(8000);
|
||||||
|
|
||||||
|
// Verify grid exists with better error handling
|
||||||
|
cy.log('[STEP 5] Verifying grid exists');
|
||||||
|
DatabaseGridSelectors.grid().should('exist', { timeout: 15000 });
|
||||||
|
|
||||||
|
// Wait for cells to appear
|
||||||
|
cy.log('[STEP 5.1] Waiting for cells to appear');
|
||||||
|
DatabaseGridSelectors.cells().should('have.length.at.least', 1);
|
||||||
|
|
||||||
|
// Add new column as SingleSelect
|
||||||
|
cy.log('[STEP 6] Adding new SingleSelect column');
|
||||||
|
PropertyMenuSelectors.newPropertyButton().first().scrollIntoView().click({ force: true });
|
||||||
|
waitForReactUpdate(3000);
|
||||||
|
|
||||||
|
// Check if property menu is open and change to SingleSelect
|
||||||
|
cy.log('[STEP 7] Changing column type to SingleSelect');
|
||||||
|
cy.get('body').then($body => {
|
||||||
|
if ($body.find('[data-testid="property-type-trigger"]').length > 0) {
|
||||||
|
PropertyMenuSelectors.propertyTypeTrigger().first().click({ force: true });
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
PropertyMenuSelectors.propertyTypeOption(FieldType.SingleSelect).click({ force: true });
|
||||||
|
waitForReactUpdate(2000);
|
||||||
|
} else {
|
||||||
|
// Try clicking on the field header first
|
||||||
|
GridFieldSelectors.allFieldHeaders().last().scrollIntoView().click({ force: true });
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
PropertyMenuSelectors.propertyTypeTrigger().first().click({ force: true });
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
PropertyMenuSelectors.propertyTypeOption(FieldType.SingleSelect).click({ force: true });
|
||||||
|
waitForReactUpdate(2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close menu
|
||||||
|
cy.get('body').type('{esc}{esc}');
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
|
||||||
|
// Add some select options by clicking on cells
|
||||||
|
cy.log('[STEP 8] Adding select options to cells');
|
||||||
|
|
||||||
|
// First try to find select cells
|
||||||
|
cy.get('body').then($body => {
|
||||||
|
const selectCells = $body.find('[data-testid^="select-option-cell-"]');
|
||||||
|
|
||||||
|
if (selectCells.length > 0) {
|
||||||
|
cy.log(`[STEP 9] Found ${selectCells.length} select cells`);
|
||||||
|
|
||||||
|
// Click first cell with force and add option
|
||||||
|
SingleSelectSelectors.allSelectOptionCells().first().click({ force: true });
|
||||||
|
waitForReactUpdate(500);
|
||||||
|
cy.focused().type('Option A{enter}');
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
|
||||||
|
// Add second option if possible
|
||||||
|
if (selectCells.length > 1) {
|
||||||
|
SingleSelectSelectors.allSelectOptionCells().eq(1).click({ force: true });
|
||||||
|
waitForReactUpdate(500);
|
||||||
|
cy.focused().type('Option B{enter}');
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cy.log('[STEP 9] No select cells found, using regular cells');
|
||||||
|
|
||||||
|
// Get all rows and find cells in the newly added column
|
||||||
|
DatabaseGridSelectors.rows().first().within(() => {
|
||||||
|
// Click the last cell in this row (should be the new column)
|
||||||
|
DatabaseGridSelectors.cells().last().click({ force: true });
|
||||||
|
waitForReactUpdate(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Type option A
|
||||||
|
cy.focused().type('Option A{enter}');
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
|
||||||
|
// Try second row
|
||||||
|
DatabaseGridSelectors.rows().eq(1).within(() => {
|
||||||
|
DatabaseGridSelectors.cells().last().click({ force: true });
|
||||||
|
waitForReactUpdate(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.focused().type('Option B{enter}');
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now open the field header menu to convert to RichText
|
||||||
|
cy.log('[STEP 10] Opening field menu to convert to RichText');
|
||||||
|
GridFieldSelectors.allFieldHeaders().last().click({ force: true });
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
|
||||||
|
// Click edit property if available
|
||||||
|
cy.get('body').then($body => {
|
||||||
|
if ($body.find('[data-testid="grid-field-edit-property"]').length > 0) {
|
||||||
|
PropertyMenuSelectors.editPropertyMenuItem().click();
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Change type to RichText
|
||||||
|
cy.log('[STEP 11] Converting SingleSelect to RichText');
|
||||||
|
PropertyMenuSelectors.propertyTypeTrigger().click({ force: true });
|
||||||
|
waitForReactUpdate(500);
|
||||||
|
PropertyMenuSelectors.propertyTypeOption(FieldType.RichText).click({ force: true });
|
||||||
|
waitForReactUpdate(2000);
|
||||||
|
|
||||||
|
// Close menu
|
||||||
|
cy.get('body').type('{esc}{esc}');
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
|
||||||
|
// Verify the cells now show text representation
|
||||||
|
cy.log('[STEP 12] Verifying text representation of select options');
|
||||||
|
DatabaseGridSelectors.cells().then($cells => {
|
||||||
|
// Check if any cell contains "Option A" or "Option B" as text
|
||||||
|
let foundOptionA = false;
|
||||||
|
let foundOptionB = false;
|
||||||
|
|
||||||
|
$cells.each((_, cell) => {
|
||||||
|
const text = cell.textContent || '';
|
||||||
|
if (text.includes('Option A')) foundOptionA = true;
|
||||||
|
if (text.includes('Option B')) foundOptionB = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (foundOptionA || foundOptionB) {
|
||||||
|
cy.log('[STEP 13] Text representation confirmed - found option text');
|
||||||
|
} else {
|
||||||
|
cy.log('[STEP 13] Text representation may be empty or different');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert back to SingleSelect
|
||||||
|
cy.log('[STEP 14] Converting back to SingleSelect');
|
||||||
|
GridFieldSelectors.allFieldHeaders().last().click({ force: true });
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
|
||||||
|
// Click edit property if available
|
||||||
|
cy.get('body').then($body => {
|
||||||
|
if ($body.find('[data-testid="grid-field-edit-property"]').length > 0) {
|
||||||
|
PropertyMenuSelectors.editPropertyMenuItem().click();
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Change type back to SingleSelect
|
||||||
|
cy.log('[STEP 15] Changing type back to SingleSelect');
|
||||||
|
PropertyMenuSelectors.propertyTypeTrigger().click({ force: true });
|
||||||
|
waitForReactUpdate(500);
|
||||||
|
PropertyMenuSelectors.propertyTypeOption(FieldType.SingleSelect).click({ force: true });
|
||||||
|
waitForReactUpdate(2000);
|
||||||
|
|
||||||
|
// Close menu
|
||||||
|
cy.get('body').type('{esc}{esc}');
|
||||||
|
waitForReactUpdate(1000);
|
||||||
|
|
||||||
|
// Verify select options are displayed again
|
||||||
|
cy.log('[STEP 16] Verifying select options are displayed again');
|
||||||
|
cy.get('body').then($body => {
|
||||||
|
const selectCells = $body.find('[data-testid^="select-option-cell-"]');
|
||||||
|
if (selectCells.length > 0) {
|
||||||
|
cy.log(`[STEP 17] Success! Found ${selectCells.length} select option cells after conversion`);
|
||||||
|
|
||||||
|
// Click on a cell to verify options are still available
|
||||||
|
SingleSelectSelectors.allSelectOptionCells().first().click();
|
||||||
|
waitForReactUpdate(500);
|
||||||
|
|
||||||
|
// Check if select menu appears
|
||||||
|
cy.get('body').then($body => {
|
||||||
|
if ($body.find('[data-testid="select-option-menu"]').length > 0) {
|
||||||
|
cy.log('[STEP 18] Select option menu opened - options preserved!');
|
||||||
|
} else {
|
||||||
|
cy.log('[STEP 18] Select cells exist but menu behavior may differ');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cy.log('[STEP 17] Select cells may be using different testid or rendering differently');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.log('[STEP 19] Field type conversion test completed');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -170,13 +170,27 @@ export class AuthTestUtils {
|
|||||||
// This endpoint creates the user in the AppFlowy backend
|
// This endpoint creates the user in the AppFlowy backend
|
||||||
cy.task('log', 'Calling verify endpoint to create user profile');
|
cy.task('log', 'Calling verify endpoint to create user profile');
|
||||||
|
|
||||||
// Make the verify call - this creates the user profile in AppFlowy backend
|
// Make the verify call with retry logic for CI environment
|
||||||
return cy.request({
|
const verifyWithRetry = (retries = 3): Cypress.Chainable<any> => {
|
||||||
method: 'GET',
|
return cy.request({
|
||||||
url: `${this.config.baseUrl}/api/user/verify/${accessToken}`,
|
method: 'GET',
|
||||||
failOnStatusCode: false,
|
url: `${this.config.baseUrl}/api/user/verify/${accessToken}`,
|
||||||
}).then((verifyResponse) => {
|
failOnStatusCode: false,
|
||||||
cy.task('log', `Verify response status: ${verifyResponse.status}`);
|
timeout: 30000,
|
||||||
|
}).then((verifyResponse) => {
|
||||||
|
cy.task('log', `Verify response status: ${verifyResponse.status}`);
|
||||||
|
|
||||||
|
// If we get a 502 or 503 error, retry
|
||||||
|
if ((verifyResponse.status === 502 || verifyResponse.status === 503) && retries > 0) {
|
||||||
|
cy.task('log', `Retrying verify endpoint, ${retries} attempts remaining`);
|
||||||
|
return cy.wait(2000).then(() => verifyWithRetry(retries - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cy.wrap(verifyResponse);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return verifyWithRetry().then((verifyResponse) => {
|
||||||
|
|
||||||
// Now refresh the token to get session data
|
// Now refresh the token to get session data
|
||||||
return cy.request({
|
return cy.request({
|
||||||
|
|||||||
@@ -220,18 +220,15 @@ export const DatabaseGridSelectors = {
|
|||||||
* Single Select Column selectors
|
* Single Select Column selectors
|
||||||
*/
|
*/
|
||||||
export const SingleSelectSelectors = {
|
export const SingleSelectSelectors = {
|
||||||
// Select option cell
|
// Select option cell by row and field ID
|
||||||
selectOptionCell: (rowId: string, fieldId: string) => cy.get(byTestId(`select-option-cell-${rowId}-${fieldId}`)),
|
selectOptionCell: (rowId: string, fieldId: string) => cy.get(byTestId(`select-option-cell-${rowId}-${fieldId}`)),
|
||||||
|
|
||||||
// Select option in dropdown
|
|
||||||
selectOption: (optionId: string) => cy.get(byTestId(`select-option-${optionId}`)),
|
|
||||||
|
|
||||||
// New property button in grid header
|
|
||||||
newPropertyButton: () => cy.get(byTestId('grid-new-property-button')),
|
|
||||||
|
|
||||||
// All select option cells
|
// All select option cells
|
||||||
allSelectOptionCells: () => cy.get('[data-testid^="select-option-cell-"]'),
|
allSelectOptionCells: () => cy.get('[data-testid^="select-option-cell-"]'),
|
||||||
|
|
||||||
|
// Select option in dropdown by option ID
|
||||||
|
selectOption: (optionId: string) => cy.get(byTestId(`select-option-${optionId}`)),
|
||||||
|
|
||||||
// Select option menu popover
|
// Select option menu popover
|
||||||
selectOptionMenu: () => cy.get(byTestId('select-option-menu')),
|
selectOptionMenu: () => cy.get(byTestId('select-option-menu')),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user