fix(core): can not preview image in shared page (#7466)

FIx BS-798
This commit is contained in:
L-Sun
2024-07-18 06:33:52 +00:00
parent 71ddb1f841
commit 9160469a18
9 changed files with 207 additions and 124 deletions

View File

@@ -97,9 +97,7 @@ const usePatchSpecs = (page: Doc, shared: boolean, mode: DocMode) => {
patchReferenceRenderer(patched, reactToLit, referenceRenderer), patchReferenceRenderer(patched, reactToLit, referenceRenderer),
confirmModal confirmModal
); );
if (!page.readonly) { patched = patchPeekViewService(patched, peekViewService);
patched = patchPeekViewService(patched, peekViewService);
}
if (!page.readonly) { if (!page.readonly) {
patched = patchQuickSearchService(patched, framework); patched = patchQuickSearchService(patched, framework);
} }

View File

@@ -514,7 +514,7 @@ export function patchQuickSearchService(
@customElement('affine-linked-doc-ref-block') @customElement('affine-linked-doc-ref-block')
// @ts-expect-error ignore private warning for overriding _load // @ts-expect-error ignore private warning for overriding _load
export class LinkedDocBlockComponent extends EmbedLinkedDocBlockComponent { export class LinkedDocBlockComponent extends EmbedLinkedDocBlockComponent {
override _load() { override async _load() {
this.isBannerEmpty = true; this.isBannerEmpty = true;
} }
} }

View File

@@ -419,14 +419,18 @@ const ImagePreviewModalImpl = ({
icon={<CopyIcon />} icon={<CopyIcon />}
onClick={copyHandler} onClick={copyHandler}
/> />
<div className={styles.dividerStyle}></div> {blockModel && !blockModel.doc.readonly && (
<ButtonWithTooltip <>
data-testid="delete-button" <div className={styles.dividerStyle}></div>
tooltip="Delete" <ButtonWithTooltip
icon={<DeleteIcon />} data-testid="delete-button"
disabled={blocks.length === 0} tooltip="Delete"
onClick={() => deleteHandler(cursor)} icon={<DeleteIcon />}
/> disabled={blocks.length === 0}
onClick={() => deleteHandler(cursor)}
/>
</>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -33,6 +33,7 @@ import { AppContainer } from '../../components/affine/app-container';
import { PageDetailEditor } from '../../components/page-detail-editor'; import { PageDetailEditor } from '../../components/page-detail-editor';
import { SharePageNotFoundError } from '../../components/share-page-not-found-error'; import { SharePageNotFoundError } from '../../components/share-page-not-found-error';
import { MainContainer } from '../../components/workspace'; import { MainContainer } from '../../components/workspace';
import { PeekViewManagerModal } from '../../modules/peek-view';
import { CloudBlobStorage } from '../../modules/workspace-engine/impls/engine/blob-cloud'; import { CloudBlobStorage } from '../../modules/workspace-engine/impls/engine/blob-cloud';
import * as styles from './share-detail-page.css'; import * as styles from './share-detail-page.css';
import { ShareFooter } from './share-footer'; import { ShareFooter } from './share-footer';
@@ -253,6 +254,7 @@ export const Component = () => {
</div> </div>
</div> </div>
</MainContainer> </MainContainer>
<PeekViewManagerModal />
</AppContainer> </AppContainer>
</FrameworkScope> </FrameworkScope>
</FrameworkScope> </FrameworkScope>

View File

@@ -5,10 +5,8 @@ import {
addUserToWorkspace, addUserToWorkspace,
createRandomUser, createRandomUser,
enableCloudWorkspace, enableCloudWorkspace,
enableCloudWorkspaceFromShareButton,
loginUser, loginUser,
} from '@affine-test/kit/utils/cloud'; } from '@affine-test/kit/utils/cloud';
import { clickEdgelessModeButton } from '@affine-test/kit/utils/editor';
import { import {
clickNewPageButton, clickNewPageButton,
getBlockSuiteEditorTitle, getBlockSuiteEditorTitle,
@@ -37,89 +35,6 @@ test.beforeEach(async ({ page }) => {
await loginUser(page, user.email); await loginUser(page, user.email);
}); });
test('can enable share page', async ({ page, browser }) => {
await page.reload();
await waitForEditorLoad(page);
await createLocalWorkspace(
{
name: 'test',
},
page
);
await enableCloudWorkspaceFromShareButton(page);
const title = getBlockSuiteEditorTitle(page);
await title.pressSequentially('TEST TITLE', {
delay: 50,
});
await page.keyboard.press('Enter', { delay: 50 });
await page.keyboard.type('TEST CONTENT', { delay: 50 });
await page.getByTestId('cloud-share-menu-button').click();
await page.getByTestId('share-menu-create-link-button').click();
await page.getByTestId('share-menu-copy-link-button').click();
// check share page is accessible
{
const context = await browser.newContext();
await skipOnboarding(context);
const url: string = await page.evaluate(() =>
navigator.clipboard.readText()
);
const page2 = await context.newPage();
await page2.goto(url);
await waitForEditorLoad(page2);
const title = getBlockSuiteEditorTitle(page2);
await expect(title).toContainText('TEST TITLE');
expect(page2.locator('affine-paragraph').first()).toContainText(
'TEST CONTENT'
);
}
});
test('share page with default edgeless', async ({ page, browser }) => {
await page.reload();
await waitForEditorLoad(page);
await createLocalWorkspace(
{
name: 'test',
},
page
);
await enableCloudWorkspaceFromShareButton(page);
const title = getBlockSuiteEditorTitle(page);
await title.pressSequentially('TEST TITLE', {
delay: 50,
});
await page.keyboard.press('Enter', { delay: 50 });
await page.keyboard.type('TEST CONTENT', { delay: 50 });
await clickEdgelessModeButton(page);
await expect(page.locator('affine-edgeless-root')).toBeVisible({
timeout: 1000,
});
await page.getByTestId('cloud-share-menu-button').click();
await page.getByTestId('share-menu-create-link-button').click();
await page.getByTestId('share-menu-copy-link-button').click();
// check share page is accessible
{
const context = await browser.newContext();
await skipOnboarding(context);
const url: string = await page.evaluate(() =>
navigator.clipboard.readText()
);
const page2 = await context.newPage();
await page2.goto(url);
await waitForEditorLoad(page2);
await expect(page.locator('affine-edgeless-root')).toBeVisible({
timeout: 1000,
});
expect(page2.locator('affine-paragraph').first()).toContainText(
'TEST CONTENT'
);
const editButton = page2.getByTestId('share-page-edit-button');
await expect(editButton).not.toBeVisible();
}
});
// SKIP until BS-671 fix // SKIP until BS-671 fix
test.skip('can collaborate with other user and name should display when editing', async ({ test.skip('can collaborate with other user and name should display when editing', async ({
page, page,

View File

@@ -0,0 +1,151 @@
import { skipOnboarding, test } from '@affine-test/kit/playwright';
import {
createRandomUser,
enableCloudWorkspaceFromShareButton,
loginUser,
} from '@affine-test/kit/utils/cloud';
import { clickEdgelessModeButton } from '@affine-test/kit/utils/editor';
import { importImage } from '@affine-test/kit/utils/image';
import {
getBlockSuiteEditorTitle,
waitForEditorLoad,
} from '@affine-test/kit/utils/page-logic';
import { createLocalWorkspace } from '@affine-test/kit/utils/workspace';
import { expect } from '@playwright/test';
let user: {
id: string;
name: string;
email: string;
password: string;
};
test.beforeEach(async () => {
user = await createRandomUser();
});
test.beforeEach(async ({ page }) => {
await loginUser(page, user.email);
});
test('can enable share page', async ({ page, browser }) => {
await page.reload();
await waitForEditorLoad(page);
await createLocalWorkspace(
{
name: 'test',
},
page
);
await enableCloudWorkspaceFromShareButton(page);
const title = getBlockSuiteEditorTitle(page);
await title.pressSequentially('TEST TITLE', {
delay: 50,
});
await page.keyboard.press('Enter', { delay: 50 });
await page.keyboard.type('TEST CONTENT', { delay: 50 });
await page.getByTestId('cloud-share-menu-button').click();
await page.getByTestId('share-menu-create-link-button').click();
await page.getByTestId('share-menu-copy-link-button').click();
// check share page is accessible
{
const context = await browser.newContext();
await skipOnboarding(context);
const url: string = await page.evaluate(() =>
navigator.clipboard.readText()
);
const page2 = await context.newPage();
await page2.goto(url);
await waitForEditorLoad(page2);
const title = getBlockSuiteEditorTitle(page2);
await expect(title).toContainText('TEST TITLE');
expect(page2.locator('affine-paragraph').first()).toContainText(
'TEST CONTENT'
);
}
});
test('share page with default edgeless', async ({ page, browser }) => {
await page.reload();
await waitForEditorLoad(page);
await createLocalWorkspace(
{
name: 'test',
},
page
);
await enableCloudWorkspaceFromShareButton(page);
const title = getBlockSuiteEditorTitle(page);
await title.pressSequentially('TEST TITLE', {
delay: 50,
});
await page.keyboard.press('Enter', { delay: 50 });
await page.keyboard.type('TEST CONTENT', { delay: 50 });
await clickEdgelessModeButton(page);
await expect(page.locator('affine-edgeless-root')).toBeVisible({
timeout: 1000,
});
await page.getByTestId('cloud-share-menu-button').click();
await page.getByTestId('share-menu-create-link-button').click();
await page.getByTestId('share-menu-copy-link-button').click();
// check share page is accessible
{
const context = await browser.newContext();
await skipOnboarding(context);
const url: string = await page.evaluate(() =>
navigator.clipboard.readText()
);
const page2 = await context.newPage();
await page2.goto(url);
await waitForEditorLoad(page2);
await expect(page.locator('affine-edgeless-root')).toBeVisible({
timeout: 1000,
});
expect(page2.locator('affine-paragraph').first()).toContainText(
'TEST CONTENT'
);
const editButton = page2.getByTestId('share-page-edit-button');
await expect(editButton).not.toBeVisible();
}
});
test('image preview should should be shown', async ({ page, browser }) => {
await page.reload();
await waitForEditorLoad(page);
await createLocalWorkspace(
{
name: 'test',
},
page
);
await enableCloudWorkspaceFromShareButton(page);
const title = getBlockSuiteEditorTitle(page);
await title.click();
await page.keyboard.press('Enter');
await importImage(page, 'http://localhost:8081/large-image.png');
await page.getByTestId('cloud-share-menu-button').click();
await page.getByTestId('share-menu-create-link-button').click();
await page.getByTestId('share-menu-copy-link-button').click();
// check share page is accessible
{
const context = await browser.newContext();
await skipOnboarding(context);
const url: string = await page.evaluate(() =>
navigator.clipboard.readText()
);
const page2 = await context.newPage();
await page2.goto(url);
await waitForEditorLoad(page2);
await page.locator('affine-page-image').first().dblclick();
const locator = page.getByTestId('image-preview-modal');
await expect(locator).toBeVisible();
await page.getByTestId('image-preview-close-button').first().click();
await page.waitForTimeout(500);
await expect(locator).not.toBeVisible();
}
});

View File

@@ -10,7 +10,7 @@ const config: PlaywrightTestConfig = {
timeout: 120_000, timeout: 120_000,
outputDir: testResultDir, outputDir: testResultDir,
use: { use: {
baseURL: 'http://localhost:8081/', baseURL: 'http://localhost:8080/',
browserName: browserName:
(process.env.BROWSER as PlaywrightWorkerOptions['browserName']) ?? (process.env.BROWSER as PlaywrightWorkerOptions['browserName']) ??
'chromium', 'chromium',
@@ -26,6 +26,16 @@ const config: PlaywrightTestConfig = {
retries: 1, retries: 1,
reporter: process.env.CI ? 'github' : 'list', reporter: process.env.CI ? 'github' : 'list',
webServer: [ webServer: [
{
command: 'yarn run serve:test-static',
port: 8081,
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
env: {
COVERAGE: process.env.COVERAGE || 'false',
ENABLE_DEBUG_PAGE: '1',
},
},
// Intentionally not building the web, reminds you to run it by yourself. // Intentionally not building the web, reminds you to run it by yourself.
{ {
command: 'yarn -T run start:web-static', command: 'yarn -T run start:web-static',

View File

@@ -2,41 +2,16 @@
import fs from 'node:fs'; import fs from 'node:fs';
import { test } from '@affine-test/kit/playwright'; import { test } from '@affine-test/kit/playwright';
import { importImage } from '@affine-test/kit/utils/image';
import { openHomePage } from '@affine-test/kit/utils/load-page'; import { openHomePage } from '@affine-test/kit/utils/load-page';
import { import {
clickNewPageButton, clickNewPageButton,
focusInlineEditor,
getBlockSuiteEditorTitle, getBlockSuiteEditorTitle,
waitForEditorLoad, waitForEditorLoad,
} from '@affine-test/kit/utils/page-logic'; } from '@affine-test/kit/utils/page-logic';
import type { Page } from '@playwright/test'; import type { Page } from '@playwright/test';
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
async function importImage(page: Page, url: string) {
await focusInlineEditor(page);
await page.evaluate(
([url]) => {
const clipData = {
'text/html': `<img alt={'Sample image'} src=${url} />`,
};
const e = new ClipboardEvent('paste', {
clipboardData: new DataTransfer(),
});
Object.defineProperty(e, 'target', {
writable: false,
value: document,
});
Object.entries(clipData).forEach(([key, value]) => {
e.clipboardData?.setData(key, value);
});
document.dispatchEvent(e);
},
[url]
);
// TODO(@catsjuice): wait for image to be loaded more reliably
await page.waitForTimeout(1000);
}
async function closeImagePreviewModal(page: Page) { async function closeImagePreviewModal(page: Page) {
await page.getByTestId('image-preview-close-button').first().click(); await page.getByTestId('image-preview-close-button').first().click();
await page.waitForTimeout(500); await page.waitForTimeout(500);

28
tests/kit/utils/image.ts Normal file
View File

@@ -0,0 +1,28 @@
import type { Page } from '@playwright/test';
import { focusInlineEditor } from './page-logic';
export async function importImage(page: Page, url: string) {
await focusInlineEditor(page);
await page.evaluate(
([url]) => {
const clipData = {
'text/html': `<img alt={'Sample image'} src=${url} />`,
};
const e = new ClipboardEvent('paste', {
clipboardData: new DataTransfer(),
});
Object.defineProperty(e, 'target', {
writable: false,
value: document,
});
Object.entries(clipData).forEach(([key, value]) => {
e.clipboardData?.setData(key, value);
});
document.dispatchEvent(e);
},
[url]
);
// TODO(@catsjuice): wait for image to be loaded more reliably
await page.waitForTimeout(1000);
}