Files
AppFlowy-Web/cypress/e2e/account/avatar/avatar-header.cy.ts
2025-11-17 15:31:02 +08:00

283 lines
11 KiB
TypeScript

import { TestTool } from '../../../support/page-utils';
import { PageSelectors } from '../../../support/selectors';
import { testLog } from '../../../support/test-helpers';
import { avatarTestUtils } from './avatar-test-utils';
const { generateRandomEmail, setupBeforeEach, imports } = avatarTestUtils;
const { APP_EVENTS, updateWorkspaceMemberAvatar, AuthTestUtils, AvatarSelectors, dbUtils } = imports;
describe('Avatar Header Display', () => {
beforeEach(() => {
setupBeforeEach();
});
describe('Header Avatar Display (Top Right Corner)', () => {
it('should display avatar in header top right corner after setting workspace avatar', () => {
const testEmail = generateRandomEmail();
const authUtils = new AuthTestUtils();
const testAvatarUrl = 'https://api.dicebear.com/7.x/avataaars/svg?seed=header-test';
testLog.info('Step 1: Visit login page');
cy.visit('/login', { failOnStatusCode: false });
cy.wait(2000);
testLog.info('Step 2: Sign in with test account');
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url({ timeout: 30000 }).should('include', '/app');
cy.wait(3000);
testLog.info('Step 3: Set avatar via workspace member profile API');
dbUtils.getCurrentWorkspaceId().then((workspaceId) => {
expect(workspaceId).to.not.be.null;
// Update avatar and wait for it to complete
cy.wrap(null).then(() => {
return updateWorkspaceMemberAvatar(workspaceId!, testAvatarUrl);
}).then((response) => {
expect(response.status).to.equal(200);
});
cy.wait(2000);
cy.reload();
cy.wait(3000);
testLog.info('Step 4: Interact with editor to trigger collaborative user awareness');
// Expand space first to make pages visible
TestTool.expandSpace(0);
cy.wait(1000);
// Wait for pages to be visible
PageSelectors.names().should('be.visible', { timeout: 10000 });
// Click on a page to open editor
PageSelectors.names().first().then($page => {
cy.wrap($page).click({ force: true });
});
cy.wait(2000);
// Interact with editor to make user appear in collaborative users
cy.get('[contenteditable="true"]').then(($editors) => {
if ($editors.length > 0) {
// Find main editor (not title)
let editorFound = false;
$editors.each((index, el) => {
const $el = Cypress.$(el);
if (!$el.attr('data-testid')?.includes('title') && !$el.hasClass('editor-title')) {
cy.wrap(el).click({ force: true });
cy.wait(500);
cy.wrap(el).type(' ', { force: true }); // Type space to trigger awareness
editorFound = true;
return false;
}
});
if (!editorFound && $editors.length > 0) {
cy.wrap($editors.last()).click({ force: true });
cy.wait(500);
cy.wrap($editors.last()).type(' ', { force: true });
}
}
});
cy.wait(2000);
testLog.info('Step 5: Verify avatar appears in header top right corner');
// Wait for header to be visible
cy.get('.appflowy-top-bar').should('be.visible');
// Check if avatar container exists in header (collaborative users area)
// The current user's avatar will appear there when they're actively editing
testLog.info('Header avatar area should be visible');
AvatarSelectors.headerAvatarContainer().should('exist');
// Verify avatar image or fallback is present
cy.get('.appflowy-top-bar [data-slot="avatar"]').should('have.length.at.least', 1);
});
});
});
it('should display emoji avatar in header when emoji is set', () => {
const testEmail = generateRandomEmail();
const authUtils = new AuthTestUtils();
const testEmoji = '🎨';
testLog.info('Step 1: Visit login page');
cy.visit('/login', { failOnStatusCode: false });
cy.wait(2000);
testLog.info('Step 2: Sign in with test account');
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url({ timeout: 30000 }).should('include', '/app');
cy.wait(3000);
testLog.info('Step 3: Set emoji avatar via API');
dbUtils.getCurrentWorkspaceId().then((workspaceId) => {
expect(workspaceId).to.not.be.null;
// Update avatar and wait for it to complete
cy.wrap(null).then(() => {
return updateWorkspaceMemberAvatar(workspaceId!, testEmoji);
}).then((response) => {
expect(response.status).to.equal(200);
});
cy.wait(2000);
cy.reload();
cy.wait(3000);
testLog.info('Step 4: Interact with editor to trigger collaborative user awareness');
// Expand space first to make pages visible
TestTool.expandSpace(0);
cy.wait(1000);
// Wait for pages to be visible
PageSelectors.names().should('be.visible', { timeout: 10000 });
// Click on a page to open editor
PageSelectors.names().first().then($page => {
cy.wrap($page).click({ force: true });
});
cy.wait(2000);
// Interact with editor
cy.get('[contenteditable="true"]').then(($editors) => {
if ($editors.length > 0) {
let editorFound = false;
$editors.each((index, el) => {
const $el = Cypress.$(el);
if (!$el.attr('data-testid')?.includes('title') && !$el.hasClass('editor-title')) {
cy.wrap(el).click({ force: true });
cy.wait(500);
cy.wrap(el).type(' ', { force: true });
editorFound = true;
return false;
}
});
if (!editorFound && $editors.length > 0) {
cy.wrap($editors.last()).click({ force: true });
cy.wait(500);
cy.wrap($editors.last()).type(' ', { force: true });
}
}
});
cy.wait(2000);
testLog.info('Step 5: Verify emoji appears in header avatar fallback');
cy.get('.appflowy-top-bar').should('be.visible');
// When user is actively editing, their avatar should appear in header
// Emoji avatars show in fallback
testLog.info('Header should be visible with avatar area');
AvatarSelectors.headerAvatarContainer().should('exist');
// Verify emoji appears in fallback
cy.get('.appflowy-top-bar [data-slot="avatar"]').should('have.length.at.least', 1);
AvatarSelectors.headerAvatarFallback(0).should('contain.text', testEmoji);
});
});
});
it('should update header avatar when workspace member profile notification is received', () => {
const testEmail = generateRandomEmail();
const authUtils = new AuthTestUtils();
const testAvatarUrl = 'https://api.dicebear.com/7.x/avataaars/svg?seed=header-notification';
testLog.info('Step 1: Visit login page');
cy.visit('/login', { failOnStatusCode: false });
cy.wait(2000);
testLog.info('Step 2: Sign in with test account');
authUtils.signInWithTestUrl(testEmail).then(() => {
cy.url({ timeout: 30000 }).should('include', '/app');
cy.wait(3000);
testLog.info('Step 3: Get user UUID and workspace ID');
dbUtils.getCurrentWorkspaceId().then((workspaceId) => {
expect(workspaceId).to.not.be.null;
dbUtils.getCurrentUserUuid().then((userUuid) => {
expect(userUuid).to.not.be.null;
testLog.info('Step 4: Simulate workspace member profile changed notification');
cy.window().then((win) => {
const emitter = (win as typeof window & {
__APPFLOWY_EVENT_EMITTER__?: { emit: (...args: unknown[]) => void };
}).__APPFLOWY_EVENT_EMITTER__;
expect(emitter, 'Event emitter should be available').to.exist;
// Simulate notification with avatar URL update
emitter?.emit(APP_EVENTS.WORKSPACE_MEMBER_PROFILE_CHANGED, {
userUuid: userUuid,
name: 'Test User',
avatarUrl: testAvatarUrl,
});
});
cy.wait(2000);
testLog.info('Step 5: Verify avatar is updated in database');
dbUtils.getWorkspaceMemberProfile(workspaceId!, userUuid!).then((profile) => {
expect(profile).to.not.be.null;
expect(profile?.avatar_url).to.equal(testAvatarUrl);
});
testLog.info('Step 6: Interact with editor to trigger collaborative user awareness');
// Expand space first to make pages visible
TestTool.expandSpace(0);
cy.wait(1000);
// Wait for pages to be visible
PageSelectors.names().should('be.visible', { timeout: 10000 });
// Click on a page to open editor
PageSelectors.names().first().then($page => {
cy.wrap($page).click({ force: true });
});
cy.wait(2000);
// Interact with editor
cy.get('[contenteditable="true"]').then(($editors) => {
if ($editors.length > 0) {
let editorFound = false;
$editors.each((index, el) => {
const $el = Cypress.$(el);
if (!$el.attr('data-testid')?.includes('title') && !$el.hasClass('editor-title')) {
cy.wrap(el).click({ force: true });
cy.wait(500);
cy.wrap(el).type(' ', { force: true });
editorFound = true;
return false;
}
});
if (!editorFound && $editors.length > 0) {
cy.wrap($editors.last()).click({ force: true });
cy.wait(500);
cy.wrap($editors.last()).type(' ', { force: true });
}
}
});
cy.wait(2000);
testLog.info('Step 7: Verify header avatar area is visible and updated');
cy.get('.appflowy-top-bar').should('be.visible');
AvatarSelectors.headerAvatarContainer().should('exist');
// Verify avatar appears in header
cy.get('.appflowy-top-bar [data-slot="avatar"]').should('have.length.at.least', 1);
// Verify the avatar image uses the updated URL (if image is loaded)
// The avatar might show as image or fallback depending on loading state
// We already verified the database update in Step 5, so just verify avatar container exists
testLog.info('Avatar container verified in header - database update confirmed in Step 5');
});
});
});
});
});
});