Skip to content

Commit

Permalink
Editor integration tests (#831)
Browse files Browse the repository at this point in the history
  • Loading branch information
apedroferreira authored Sep 19, 2022
1 parent 435a6a6 commit bbaaec7
Show file tree
Hide file tree
Showing 16 changed files with 516 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export default function ComponentCatalog({ className }: ComponentCatalogProps) {

return (
<ComponentCatalogRoot
data-testid="component-catalog"
className={className}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export default function ComponentEditor({ className }: ComponentEditorProps) {
const selectedNode = selection ? appDom.getNode(dom, selection) : null;

return (
<ComponentEditorRoot className={className}>
<ComponentEditorRoot className={className} data-testid="component-editor">
{selectedNode && appDom.isElement(selectedNode) ? (
// Add key to make sure it mounts every time selected node changes
<SelectedNodeEditor key={selectedNode.id} node={selectedNode} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export default React.forwardRef<EditorCanvasHostHandle, EditorCanvasHostProps>(
</Box>
<CanvasFrame
ref={frameRef}
name="data-toolpad-canvas"
onLoad={handleFrameLoad}
src={`/app-canvas/${appId}/pages/${pageNodeId}`}
// Used by the runtime to know when to load react devtools
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,7 @@ export default function RenderOverlay({ canvasHostRef }: RenderOverlayProps) {

return (
<OverlayRoot
data-testid="page-overlay"
ref={overlayRef}
className={clsx({
[overlayClasses.nodeDrag]: isDraggingOver,
Expand Down
2 changes: 1 addition & 1 deletion packages/toolpad-app/src/toolpad/ToolpadShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ function Header({ actions, status }: HeaderProps) {
height={25}
/>
<Box
data-test-id="brand"
data-testid="brand"
sx={{
color: 'primary.main',
lineHeight: '21px',
Expand Down
5 changes: 2 additions & 3 deletions test/integration/appRename.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ToolpadHome } from '../models/ToolpadHome';
import { test, expect } from '../playwright/test';
import generateId from '../utils/generateId';
import * as locators from '../utils/locators';

test('app create/rename flow', async ({ page }) => {
const appName1 = `App ${generateId()}`;
Expand All @@ -15,7 +14,7 @@ test('app create/rename flow', async ({ page }) => {
await homeModel.createApplication({ name: appName2 });
await homeModel.goto();

await page.click(`${locators.toolpadHomeAppRow(appName1)} >> [aria-label="Application menu"]`);
await homeModel.getAppRow(appName1).locator('[aria-label="Application menu"]').click();

await page.click('[role="menuitem"]:has-text("Rename"):visible');

Expand All @@ -26,5 +25,5 @@ test('app create/rename flow', async ({ page }) => {

await page.keyboard.type(appName3);

await expect(page.locator(locators.toolpadHomeAppRow(appName3))).toBeVisible();
await expect(homeModel.getAppRow(appName3)).toBeVisible();
});
15 changes: 0 additions & 15 deletions test/integration/editor-basics/index.spec.ts

This file was deleted.

86 changes: 86 additions & 0 deletions test/integration/editor/domInput.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"root": "y3c19mb",
"nodes": {
"ft63r75": {
"id": "ft63r75",
"name": "textField1",
"type": "element",
"props": {
"label": {
"type": "const",
"value": "textField1"
}
},
"layout": {},
"parentId": "w173rcy",
"attributes": {
"component": {
"type": "const",
"value": "TextField"
}
},
"parentProp": "children",
"parentIndex": "a0"
},
"rl83rbf": {
"id": "rl83rbf",
"name": "textField2",
"type": "element",
"props": {
"label": {
"type": "const",
"value": "textField2"
}
},
"layout": {},
"parentId": "w173rcy",
"attributes": {
"component": {
"type": "const",
"value": "TextField"
}
},
"parentProp": "children",
"parentIndex": "a1"
},
"w173rcy": {
"id": "w173rcy",
"name": "pageRow",
"type": "element",
"props": {},
"layout": {},
"parentId": "y4d19z0",
"attributes": {
"component": {
"type": "const",
"value": "PageRow"
}
},
"parentProp": "children",
"parentIndex": "a0"
},
"y3c19mb": {
"id": "y3c19mb",
"name": "Application",
"type": "app",
"parentId": null,
"attributes": {},
"parentProp": null,
"parentIndex": null
},
"y4d19z0": {
"id": "y4d19z0",
"name": "page1",
"type": "page",
"parentId": "y3c19mb",
"attributes": {
"title": {
"type": "const",
"value": "Page 1"
}
},
"parentProp": "pages",
"parentIndex": "a0"
}
}
}
136 changes: 136 additions & 0 deletions test/integration/editor/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { test, expect } from '@playwright/test';
import { ToolpadHome } from '../../models/ToolpadHome';
import { ToolpadEditor } from '../../models/ToolpadEditor';
import clickCenter from '../../utils/clickCenter';
import domInput from './domInput.json';

test('can place new components from catalog', async ({ page, browserName }) => {
const homeModel = new ToolpadHome(page);
const editorModel = new ToolpadEditor(page, browserName);

await homeModel.goto();
const app = await homeModel.createApplication({});
await editorModel.goto(app.id);

await editorModel.pageRoot.waitFor();

const canvasInputLocator = editorModel.appCanvas.locator('input');

await expect(canvasInputLocator).toHaveCount(0);

const TEXT_FIELD_COMPONENT_ID = 'TextField';

// Drag in a first component

await editorModel.dragNewComponentToAppCanvas(TEXT_FIELD_COMPONENT_ID);

await expect(canvasInputLocator).toHaveCount(1);
await expect(canvasInputLocator).toBeVisible();

// Drag in a second component

await editorModel.dragNewComponentToAppCanvas(TEXT_FIELD_COMPONENT_ID);

await expect(canvasInputLocator).toHaveCount(2);
});

test('can move elements in page', async ({ page, browserName }) => {
const homeModel = new ToolpadHome(page);
const editorModel = new ToolpadEditor(page, browserName);

await homeModel.goto();
const app = await homeModel.createApplication({ dom: domInput });
await editorModel.goto(app.id);

await editorModel.pageRoot.waitFor();

const canvasMoveElementHandleSelector = ':has-text("TextField")[draggable]';

const canvasInputLocator = editorModel.appCanvas.locator('input');
const canvasMoveElementHandleLocator = editorModel.appCanvas.locator(
canvasMoveElementHandleSelector,
);

const firstTextFieldLocator = canvasInputLocator.first();
const secondTextFieldLocator = canvasInputLocator.nth(1);

await firstTextFieldLocator.focus();
await firstTextFieldLocator.fill('textField1');

await secondTextFieldLocator.focus();
await secondTextFieldLocator.fill('textField2');

await expect(firstTextFieldLocator).toHaveAttribute('value', 'textField1');
await expect(secondTextFieldLocator).toHaveAttribute('value', 'textField2');

await expect(canvasMoveElementHandleLocator).not.toBeVisible();

// Move first element by dragging it to the right side of second element

await clickCenter(page, firstTextFieldLocator);

const secondTextFieldBoundingBox = await secondTextFieldLocator.boundingBox();
expect(secondTextFieldBoundingBox).toBeDefined();

const moveTargetX = secondTextFieldBoundingBox!.x + secondTextFieldBoundingBox!.width;
const moveTargetY = secondTextFieldBoundingBox!.y + secondTextFieldBoundingBox!.height / 2;

await editorModel.dragToAppCanvas(
canvasMoveElementHandleSelector,
true,
moveTargetX,
moveTargetY,
);

await expect(firstTextFieldLocator).toHaveAttribute('value', 'textField2');
await expect(secondTextFieldLocator).toHaveAttribute('value', 'textField1');
});

test('can delete elements from page', async ({ page, browserName }) => {
const homeModel = new ToolpadHome(page);
const editorModel = new ToolpadEditor(page, browserName);

await homeModel.goto();
const app = await homeModel.createApplication({ dom: domInput });
await editorModel.goto(app.id);

await editorModel.pageRoot.waitFor();

const canvasInputLocator = editorModel.appCanvas.locator('input');
const canvasRemoveElementButtonLocator = editorModel.appCanvas.locator(
'button[aria-label="Remove element"]',
);

await expect(canvasInputLocator).toHaveCount(2);

// Delete element by clicking

await expect(canvasRemoveElementButtonLocator).not.toBeVisible();

const firstTextFieldLocator = canvasInputLocator.first();

await clickCenter(page, firstTextFieldLocator);
await canvasRemoveElementButtonLocator.click();

await expect(canvasInputLocator).toHaveCount(1);

// Delete element by pressing key

await clickCenter(page, firstTextFieldLocator);
await page.keyboard.press('Backspace');

await expect(canvasInputLocator).toHaveCount(0);
});

test('can create new component', async ({ page, browserName }) => {
const homeModel = new ToolpadHome(page);
const editorModel = new ToolpadEditor(page, browserName);

await homeModel.goto();
const app = await homeModel.createApplication({});

await editorModel.goto(app.id);

await editorModel.createPage('somePage');
await editorModel.createComponent('someComponent');
});
86 changes: 86 additions & 0 deletions test/integration/propControls/domInput.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"root": "y3c19mb",
"nodes": {
"ft63r75": {
"id": "ft63r75",
"name": "textField1",
"type": "element",
"props": {
"label": {
"type": "const",
"value": "textField1"
}
},
"layout": {},
"parentId": "w173rcy",
"attributes": {
"component": {
"type": "const",
"value": "TextField"
}
},
"parentProp": "children",
"parentIndex": "a0"
},
"rl83rbf": {
"id": "rl83rbf",
"name": "textField2",
"type": "element",
"props": {
"label": {
"type": "const",
"value": "textField2"
}
},
"layout": {},
"parentId": "w173rcy",
"attributes": {
"component": {
"type": "const",
"value": "TextField"
}
},
"parentProp": "children",
"parentIndex": "a1"
},
"w173rcy": {
"id": "w173rcy",
"name": "pageRow",
"type": "element",
"props": {},
"layout": {},
"parentId": "y4d19z0",
"attributes": {
"component": {
"type": "const",
"value": "PageRow"
}
},
"parentProp": "children",
"parentIndex": "a0"
},
"y3c19mb": {
"id": "y3c19mb",
"name": "Application",
"type": "app",
"parentId": null,
"attributes": {},
"parentProp": null,
"parentIndex": null
},
"y4d19z0": {
"id": "y4d19z0",
"name": "page1",
"type": "page",
"parentId": "y3c19mb",
"attributes": {
"title": {
"type": "const",
"value": "Page 1"
}
},
"parentProp": "pages",
"parentIndex": "a0"
}
}
}
Loading

0 comments on commit bbaaec7

Please sign in to comment.