Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions blocks/edit/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ let wsProvider;
let startPreviewing;
let stopPreviewing;

async function setUI(el, utils) {
async function setUI(el, utils, guid) {
const details = getPathDetails();
if (!details) return;

Expand Down Expand Up @@ -36,7 +36,7 @@ async function setUI(el, utils) {
}

const { daFetch } = await utils;
const { permissions } = await daFetch(details.sourceUrl, { method: 'HEAD' });
const { permissions, headers } = await daFetch(details.sourceUrl, { method: 'HEAD' });
daTitle.permissions = permissions;
daContent.permissions = permissions;

Expand All @@ -45,12 +45,17 @@ async function setUI(el, utils) {
daContent.wsProvider = undefined;
}

const docGUID = guid ?? headers?.get('x-da-id');
({
proseEl,
wsProvider,
startPreviewing,
stopPreviewing,
} = prose.default({ path: details.sourceUrl, permissions }));
} = prose.default({
path: details.sourceUrl,
permissions,
docGUID,
}, (updatedGuid) => setUI(el, utils, updatedGuid)));

daContent.proseEl = proseEl;
daContent.wsProvider = wsProvider;
Expand Down
36 changes: 34 additions & 2 deletions blocks/edit/prose/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,13 @@ function addSyncedListener(wsProvider, canWrite) {
wsProvider.on('synced', handleSynced);
}

export default function initProse({ path, permissions }) {
function getNewestGuid(guidArray) {
const guids = [...guidArray];
guids.sort((a, b) => a.ts - b.ts);
return guids.pop();
}

export default function initProse({ path, permissions, docGUID }, resetFunc) {
// Destroy ProseMirror if it already exists - GH-212
if (window.view) delete window.view;
const editor = document.createElement('div');
Expand All @@ -223,7 +229,33 @@ export default function initProse({ path, permissions }) {
createAwarenessStatusWidget(wsProvider, window);
registerErrorHandler(ydoc);

const yXmlFragment = ydoc.getXmlFragment('prosemirror');
const guidArray = ydoc.getArray('prosemirror-guids');
let curGuid;
if (docGUID) {
curGuid = docGUID;

if (getNewestGuid(guidArray) !== curGuid) {
guidArray.push([{ ts: Date.now(), guid: curGuid }]);
}
} else {
curGuid = crypto.randomUUID();
guidArray.push([{ ts: Date.now(), guid: curGuid, newDoc: true }]);
}

ydoc.on('update', () => {
// If the document has been replaced by a another document (it has been first deleted
// and then a new document has been created), reset the window to connect to the new doc.
const guids = [...guidArray];
if (guids.length === 0) {
return;
}
const latestGuid = getNewestGuid(guids);
if (latestGuid.guid !== curGuid) {
resetFunc(latestGuid.guid);
}
});

const yXmlFragment = ydoc.getXmlFragment(`prosemirror-${curGuid}`);

if (window.adobeIMS?.isSignedInUser()) {
window.adobeIMS.getProfile().then(
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/tests/browse.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { test, expect } from '@playwright/test';
import ENV from '../utils/env.js';
import { getQuery } from '../utils/page.js';


Check failure on line 5 in test/e2e/tests/browse.spec.js

View workflow job for this annotation

GitHub Actions / Running tests (20.x)

More than 1 blank line not allowed
test('Get Main Page', async ({ page }) => {
await page.goto(ENV);
await page.goto(`${ENV}/${getQuery()}`);
const html = await page.content();

expect(html).toContain('Browse - DA');
Expand Down
32 changes: 29 additions & 3 deletions test/e2e/tests/copy_rename.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2024 Adobe. All rights reserved.
* Copyright 2025 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
Expand All @@ -16,7 +16,7 @@ import { getQuery, getTestFolderURL, getTestPageURL } from '../utils/page.js';
test('Copy and Rename with Versioned document', async ({ page }, workerInfo) => {
// This test has a fairly high timeout because it waits for the document to be saved
// a number of times
test.setTimeout(60000);
test.setTimeout(1200000);

const pageURL = getTestPageURL('copyrename', workerInfo);
const orgPageName = pageURL.split('/').pop();
Expand Down Expand Up @@ -49,6 +49,7 @@ test('Copy and Rename with Versioned document', async ({ page }, workerInfo) =>
// Go back to the directory view
await page.goto(`${ENV}/${getQuery()}#/da-sites/da-status/tests`);

// Copy the document
const copyFolderURL = getTestFolderURL('copy', workerInfo);
const copyFolderName = copyFolderURL.split('/').pop();
await page.getByRole('button', { name: 'New' }).click();
Expand All @@ -65,14 +66,15 @@ test('Copy and Rename with Versioned document', async ({ page }, workerInfo) =>
await page.getByRole('link', { name: copyFolderName }).click();
await page.waitForURL(`**/da-sites/da-status/tests/${copyFolderName}`);

// Paste it in the new folder
await page.getByRole('button', { name: 'Paste' }).click();
await page.waitForTimeout(3000);
/* TODO REMOVE once #233 is fixed */ await page.reload();
const link = await page.getByRole('link', { name: orgPageName });
const href = await link.getAttribute('href');
await expect(href).toEqual(`/edit#/da-sites/da-status/tests/${copyFolderName}/${orgPageName}`);

// go back to the original to rename it
// Go back to the original to rename it
// Go to the directory view
await page.goto(`${ENV}/${getQuery()}#/da-sites/da-status/tests`);
await page.reload(); // Clears any leftover selection, if any
Expand All @@ -92,8 +94,18 @@ test('Copy and Rename with Versioned document', async ({ page }, workerInfo) =>
await page.waitForTimeout(3000);
await page.goto(`${pageURL}ren`);

// Ensure it has the latest text
await page.waitForTimeout(3000);
await expect(page.locator('div.ProseMirror')).toContainText('After versioned');

// Make some edits, ensure that they work
await page.locator('div.ProseMirror').fill('Now its renamed');
await page.waitForTimeout(3000);
await page.reload();
await page.waitForTimeout(3000);
await expect(page.locator('div.ProseMirror')).toContainText('Now its renamed');

// Restore a previous version
await page.getByRole('button', { name: 'Versions' }).click();
await page.getByText('myver', { exact: false }).click();
await page.locator('li').filter({ hasText: 'myver' }).getByRole('button').click();
Expand All @@ -102,11 +114,25 @@ test('Copy and Rename with Versioned document', async ({ page }, workerInfo) =>
// Ensure that the original text is still there
await expect(page.locator('div.ProseMirror')).toContainText('Versioned text');

// Make some further edits
await page.locator('div.ProseMirror').fill('Renamed again');
await page.waitForTimeout(3000);
await page.reload();
await page.waitForTimeout(3000);
await expect(page.locator('div.ProseMirror')).toContainText('Renamed again');

// now go to the copy
await page.goto(`${ENV}/edit${getQuery()}#/da-sites/da-status/tests/${copyFolderName}/${orgPageName}`);
await page.reload(); // Resets the versions view, shouldn't be needed TODO
await expect(page.locator('div.ProseMirror')).toContainText('After versioned');
await page.getByRole('button', { name: 'Versions' }).click();
await expect(page.getByText('Now')).toBeVisible();
await expect(page.getByText('myver')).not.toBeVisible(); // The version shouldn't be there on the copy

// Make some edits on the copy
await page.locator('div.ProseMirror').fill('Renamed copy');
await page.waitForTimeout(3000);
await page.reload();
await page.waitForTimeout(3000);
await expect(page.locator('div.ProseMirror')).toContainText('Renamed copy');
});
13 changes: 12 additions & 1 deletion test/e2e/tests/delete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ test('Empty out open editors on deleted documents', async ({ browser, page }, wo
const enteredText = `Some content entered at ${new Date()}`;
await page.locator('div.ProseMirror').fill(enteredText);

// Wait for the content to be stored in the backend
await page.waitForTimeout(3000);

// Create a second window on the same document
const page2 = await browser.newPage();
await page2.goto(url);
Expand Down Expand Up @@ -131,8 +134,16 @@ test('Empty out open editors on deleted documents', async ({ browser, page }, wo
await list.locator('sl-button.negative').locator('visible=true').click();

// Give the second window a chance to update itself
await list.waitForTimeout(10000);
await page2.waitForTimeout(3000);

// The open window should be cleared out now
await expect(page2.locator('div.ProseMirror')).not.toContainText(enteredText);

// Add some text to the second window with the stale document, it should not be saved
await page2.locator('div.ProseMirror').fill('Some new content');
await page2.waitForTimeout(5000);

list.reload();
// The document should still not be in the list, even though edits were made on the stale doc
await expect(list.locator(`a[href="/edit#/da-sites/da-status/tests/${pageName}"]`)).not.toBeVisible();
});
2 changes: 1 addition & 1 deletion test/e2e/utils/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function getEnv() {
if (!owner) {
owner = 'adobe';
}
if (branch === 'local') {
if (branch === 'local' || branch === 'localstg') {
return 'http://localhost:3000';
}
if (branch === 'local-https') {
Expand Down
3 changes: 3 additions & 0 deletions test/e2e/utils/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export function getQuery() {
if (branch === 'local') {
return '?da-admin=local&da-collab=local';
}
if (branch === 'localstg') {
return '?da-admin=stage&da-collab=stage';
}
return '';
}

Expand Down
Loading