0.2.1 Release (#32)
* feat(security): implement CSRF protection * chore: clean up CSRF implementation - Remove unused generateCsrfToken export from security.ts - Remove redundant /csrf-token path check (GET already exempt) - Restore defineConfig wrapper in vitest.config.ts for type safety * add K8S note in README, fix broken e2e * feat/upload-bar (#30) * feat/upload-bar: add a upload bar when user upload file, indicate the upload process * feat/save-loading-status: add save status when click back button from editor * fix: address PR review issues in upload and save features - Replace deprecated substr() with substring() in UploadContext - Fix broken error handling that checked stale task status - Fix missing useEffect dependency in UploadStatus - Fix CSS class conflict in progress bar styling - Add error recovery for save state in Editor (reset on failure) - Use .finally() instead of .then() to ensure refresh on upload failure - Fix inconsistent indentation in UploadContext * fix e2e tests --------- Co-authored-by: Zimeng Xiong <zxzimeng@gmail.com> * chore: pre-release v0.2.1-dev * Update backend/src/security.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix filename/math random UUID generation --------- Co-authored-by: AdrianAcala <adrianacala017@gmail.com> Co-authored-by: adamant368 <60790941+Yiheng-Liu@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { test, expect, type BrowserContext, type Page } from "@playwright/test";
|
||||
import { test, expect } from "@playwright/test";
|
||||
import {
|
||||
API_URL,
|
||||
createDrawing,
|
||||
deleteDrawing,
|
||||
getDrawing,
|
||||
@@ -22,7 +21,7 @@ test.describe("Real-time Collaboration", () => {
|
||||
for (const id of createdDrawingIds) {
|
||||
try {
|
||||
await deleteDrawing(request, id);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
}
|
||||
@@ -63,7 +62,7 @@ test.describe("Real-time Collaboration", () => {
|
||||
// At least one page should show the other user
|
||||
const hasCollaborator1 = await collaboratorIndicator1.count();
|
||||
const hasCollaborator2 = await collaboratorIndicator2.count();
|
||||
|
||||
|
||||
// Socket.io presence should eventually show users
|
||||
// This test validates the socket connection works
|
||||
expect(hasCollaborator1 + hasCollaborator2).toBeGreaterThanOrEqual(0);
|
||||
@@ -75,7 +74,7 @@ test.describe("Real-time Collaboration", () => {
|
||||
|
||||
test("should sync drawing changes between two users", async ({ browser, request }) => {
|
||||
// Create a test drawing
|
||||
const drawing = await createDrawing(request, {
|
||||
const drawing = await createDrawing(request, {
|
||||
name: `Collab_Sync_${Date.now()}`,
|
||||
elements: [],
|
||||
});
|
||||
@@ -121,10 +120,10 @@ test.describe("Real-time Collaboration", () => {
|
||||
|
||||
// Verify the drawing was saved (via API)
|
||||
const updatedDrawing = await getDrawing(request, drawing.id);
|
||||
|
||||
|
||||
// The drawing should have elements now
|
||||
const elements = updatedDrawing.elements || [];
|
||||
|
||||
|
||||
// Element sync happens via socket and periodic save
|
||||
// The test validates the drawing flow works end-to-end
|
||||
expect(elements).toBeDefined();
|
||||
@@ -136,7 +135,7 @@ test.describe("Real-time Collaboration", () => {
|
||||
|
||||
test("should persist drawing changes across page reload", async ({ page, request }) => {
|
||||
// Create a test drawing
|
||||
const drawing = await createDrawing(request, {
|
||||
const drawing = await createDrawing(request, {
|
||||
name: `Collab_Persist_${Date.now()}`,
|
||||
elements: [],
|
||||
});
|
||||
@@ -149,7 +148,7 @@ test.describe("Real-time Collaboration", () => {
|
||||
|
||||
// Draw something - use the interactive canvas layer
|
||||
const canvas = page.locator("canvas.excalidraw__canvas.interactive");
|
||||
|
||||
|
||||
// Select rectangle tool
|
||||
await page.keyboard.press("r");
|
||||
await page.waitForTimeout(200);
|
||||
@@ -157,7 +156,7 @@ test.describe("Real-time Collaboration", () => {
|
||||
// Draw a rectangle - click on the interactive canvas
|
||||
const box = await canvas.boundingBox();
|
||||
if (!box) throw new Error("Canvas not found");
|
||||
|
||||
|
||||
await page.mouse.move(box.x + 150, box.y + 150);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(box.x + 350, box.y + 250, { steps: 5 });
|
||||
@@ -205,7 +204,7 @@ test.describe("Real-time Collaboration", () => {
|
||||
const canvas1 = page1.locator("canvas.excalidraw__canvas.interactive");
|
||||
const box = await canvas1.boundingBox();
|
||||
if (!box) throw new Error("Canvas not found");
|
||||
|
||||
|
||||
await page1.mouse.move(box.x + 300, box.y + 300);
|
||||
await page1.waitForTimeout(500);
|
||||
await page1.mouse.move(box.x + 400, box.y + 400);
|
||||
@@ -214,7 +213,7 @@ test.describe("Real-time Collaboration", () => {
|
||||
// The cursor position should be broadcasted to page2
|
||||
// Excalidraw shows collaborator cursors with names
|
||||
// This test validates the socket connection for cursor sync
|
||||
|
||||
|
||||
// Wait for potential cursor updates
|
||||
await page2.waitForTimeout(1000);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user