Skip to content

Commit 7033d30

Browse files
authored
fix(e2e): repair grid multi-body coverage (#14852) (#14872)
1 parent d1c353e commit 7033d30

2 files changed

Lines changed: 70 additions & 66 deletions

File tree

test/playwright/e2e/grid/BigDataMultiBodyNL.spec.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ test.describe('Grid BigData Multi-Body Neural Link Validation', () => {
6060
// God Mode Assertion: Verify the exact backend state mirrors our action.
6161
const grids = await app.findInstances({className: 'Neo.examples.grid.bigData.GridContainer'}, ['id']);
6262
if (grids.length > 0) {
63-
const gridProps = await app.getInstanceProperties(grids[0].id, ['body.selectionModel.selectedRows']);
64-
expect(gridProps.properties['body.selectionModel.selectedRows']).toContain('neo-record-1');
63+
const gridProps = await app.getComponent(grids[0].id, ['view.selectionModel.selectedRows']);
64+
expect(gridProps['view.selectionModel.selectedRows']).toContain('neo-record-1');
6565
}
6666
});
6767

Lines changed: 68 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,110 @@
11
import { test, expect } from '../../fixtures.mjs';
22

3-
test.describe('Desktop (1280x720): Grid Multi-Body Neural Link Selection Validation', () => {
4-
test.setTimeout(90000); // DevIndex is heavy; give 90s for page render + NL mapping
5-
test.use({ viewport: { width: 1280, height: 720 } });
3+
test.describe('Desktop (1920x1080): lockedColumns Multi-Body Neural Link Selection Validation', () => {
4+
test.setTimeout(90000);
5+
test.use({ viewport: { width: 1920, height: 1080 } });
66

77
test.beforeEach(async ({ page }) => {
8-
await page.goto('/apps/devindex/index.html');
8+
await page.goto('/examples/grid/lockedColumns/');
99

10-
// Wait for grid skeleton to mount
11-
await page.waitForSelector('.neo-grid-container', { state: 'visible', timeout: 30000 });
12-
13-
// Wait for initial data stream to hit (Stop button becomes visible)
14-
const stopButton = page.locator('.devindex-stop-stream-button');
15-
await expect(stopButton).toBeVisible({ timeout: 10000 });
16-
17-
// Click the stop button immediately so we don't wait for thousands of rows.
18-
// We use force in case it's animating, and ignore errors if it somehow already hid itself.
19-
try {
20-
await stopButton.click({ timeout: 2000, force: true });
21-
} catch (e) {
22-
// Stream finished extremely fast and button auto-hid
23-
}
24-
25-
// Let UI settle for a moment after stopping
10+
await page.waitForSelector('[role="grid"]', { state: 'visible', timeout: 30000 });
2611
await page.waitForTimeout(500);
2712
});
2813

2914
test('Cross-Body Row Selection Synchronization and Verification via Neural Link', async ({ page, neuralLink }) => {
30-
// Connect directly to the App Worker
31-
const app = await neuralLink.connectToApp('DevIndex');
32-
33-
// Locate the main GridContainer manually via Main Thread DOM to prove it works
34-
const gridId = await page.evaluate(() => document.querySelector('.neo-grid-container').id);
15+
const app = await neuralLink.connectToApp('Neo.examples.grid.lockedColumns');
16+
const gridId = await resolveGridId(app);
3517

36-
// Activate RowModel natively using Neural Link (since DevIndex defaults to null on load)
3718
await app.setProperties(gridId, { 'body.selectionModel': { ntype: 'selection-grid-rowmodel' } });
3819

39-
// Let it initialize
40-
await page.waitForTimeout(200);
41-
42-
// Inspect the Grid Component directly
43-
const gridProps = await app.getComponent(gridId, ['bodyStart.id', 'body.id', 'bodyEnd.id', 'body.selectionModel', 'store', 'ntype']);
20+
await expect.poll(async () => {
21+
const props = await app.getComponent(gridId, ['view.selectionModel.id']);
22+
return props['view.selectionModel.id'];
23+
}, { timeout: 5000 }).toBeTruthy();
24+
25+
const gridProps = await app.getComponent(gridId, [
26+
'bodyStart.id',
27+
'body.id',
28+
'bodyEnd.id',
29+
'lockedStartColumns',
30+
'lockedEndColumns',
31+
'ntype',
32+
'view.selectionModel.id'
33+
]);
4434

4535
expect(gridProps.ntype).toBe('grid-container');
46-
expect(gridProps['body.selectionModel']).toBeTruthy();
36+
expect((gridProps.lockedStartColumns || []).length, 'fixture has locked-start columns').toBeGreaterThan(0);
37+
expect((gridProps.lockedEndColumns || []).length, 'fixture has locked-end columns').toBeGreaterThan(0);
38+
expect(gridProps['view.selectionModel.id']).toBeTruthy();
4739

48-
// We want to test clicking a row in the CENTER body to avoid locked-column interaction edge cases for now
49-
const centerBodyId = gridProps['body.id'];
5040
const leftBodyId = gridProps['bodyStart.id'];
41+
const centerBodyId = gridProps['body.id'];
5142
const rightBodyId = gridProps['bodyEnd.id'];
52-
const storeId = gridProps.store?.id || gridProps.store;
5343

54-
// Locate the first row in the center body
44+
expect(leftBodyId, 'locked-start body id').toBeTruthy();
45+
expect(centerBodyId, 'center body id').toBeTruthy();
46+
expect(rightBodyId, 'locked-end body id').toBeTruthy();
47+
5548
const centerBodyRow = page.locator(`#${centerBodyId} .neo-grid-row`).first();
49+
await expect(centerBodyRow).toBeVisible();
5650

57-
// Grab the recordId mapped to this DOM node
5851
const recordId = await centerBodyRow.getAttribute('data-record-id');
52+
expect(recordId, 'center row must expose a record id').toBeTruthy();
5953

60-
// It should NOT be selected yet
6154
await expect(centerBodyRow).not.toHaveClass(/neo-selected/);
6255

63-
// Native User Interaction (Clicking the center column row)
6456
await centerBodyRow.click();
6557

66-
// Visual Assertion: Wait for App Worker to reconcile and add selections
6758
await expect(centerBodyRow).toHaveClass(/neo-selected/);
6859

69-
// Mult-Body Validation: Check the left and right bodies for that same record ID
7060
const leftBodyRow = page.locator(`#${leftBodyId} .neo-grid-row[data-record-id="${recordId}"]`);
7161
const rightBodyRow = page.locator(`#${rightBodyId} .neo-grid-row[data-record-id="${recordId}"]`);
7262

73-
// They should BOTH be selected as well due to multi-body orchestration
7463
await expect(leftBodyRow).toHaveClass(/neo-selected/);
7564
await expect(rightBodyRow).toHaveClass(/neo-selected/);
7665

77-
// God Mode Assertion: Verify the exact backend state mirrors our action.
78-
// DevIndex Grid defaults to array-based selection since selectedRecordField ('selected')
79-
// does not exist on the Contributor model prototype. We check the RowModel's selectedRows array.
80-
const smId = gridProps['body.selectionModel'].id;
81-
const smProps = await app.getComponent(smId, ['selectedRows']);
82-
expect(smProps.selectedRows.includes(recordId)).toBe(true);
66+
const selectedRows = (await app.getComponent(gridId, ['view.selectionModel.selectedRows']))['view.selectionModel.selectedRows'];
67+
expect(selectedRows).toContain(recordId);
8368
});
8469

85-
test('Live Property Updation (Column Width Alignment)', async ({ page, neuralLink }) => {
86-
const app = await neuralLink.connectToApp('DevIndex');
87-
const gridId = await page.evaluate(() => document.querySelector('.neo-grid-container').id);
70+
test('Live Body Resize Path Updates Center Cells and Width Cache', async ({ page, neuralLink }) => {
71+
const app = await neuralLink.connectToApp('Neo.examples.grid.lockedColumns');
72+
const gridId = await resolveGridId(app);
73+
const { 'body.id': centerBodyId } = await app.getComponent(gridId, ['body.id']);
8874

89-
// Get the structural columns from the Grid container
90-
// Note: The dev index columns setup has multiple bodies. We need a visible column ID.
91-
const headerCells = page.locator('.neo-grid-header-button');
92-
const firstCenterCellId = await headerCells.nth(2).getAttribute('id'); // Skip start columns
75+
expect(centerBodyId, 'center body id').toBeTruthy();
9376

94-
// Just verify we can fetch the column config
95-
const colProps = await app.getComponent(firstCenterCellId, ['width', 'dataField']);
96-
const oldWidth = colProps.width;
77+
const centerBodyRow = page.locator(`#${centerBodyId} .neo-grid-row`).first();
78+
await expect(centerBodyRow).toBeVisible();
79+
80+
const totalCell = centerBodyRow.locator('[role="gridcell"]').first();
81+
await expect(totalCell).toBeVisible();
82+
83+
const beforeBox = await totalCell.boundingBox();
84+
expect(beforeBox?.width, 'Total cell width before resize').toBeGreaterThan(0);
85+
86+
const beforeProps = await app.getComponent(centerBodyId, ['availableWidth']);
87+
const newWidth = Math.round(beforeBox.width + 40);
9788

98-
// Using God Mode, forcibly alter the width of a specific column component
99-
const newWidth = oldWidth + 100;
100-
await app.setProperties(firstCenterCellId, { width: newWidth });
89+
await app.callMethod(centerBodyId, 'updateCellPositions', ['totalContributions', newWidth]);
10190

102-
// Assert: Playwright observes the CSS strictly matches the new injected God Mode constraint
103-
const targetCell = page.locator(`#${firstCenterCellId}`);
104-
await expect(targetCell).toHaveCSS('width', `${newWidth}px`);
91+
await expect(totalCell).toHaveCSS('width', `${newWidth}px`);
92+
93+
const afterProps = await app.getComponent(centerBodyId, ['availableWidth']);
94+
expect(afterProps.availableWidth).toBe(beforeProps.availableWidth + 40);
10595
});
10696
});
97+
98+
/**
99+
* Resolves the grid-container instance id from the App Worker.
100+
* @param {Object} app
101+
* @returns {Promise<String>}
102+
*/
103+
async function resolveGridId(app) {
104+
const grids = await app.findInstances({ ntype: 'grid-container' }, ['id']);
105+
const gridId = Array.isArray(grids) ? grids[0]?.id : grids?.id;
106+
107+
expect(gridId, 'a grid-container instance must exist in the bound App Worker').toBeTruthy();
108+
109+
return gridId;
110+
}

0 commit comments

Comments
 (0)