mirror of
https://github.com/enso-org/enso.git
synced 2024-11-30 05:04:21 +03:00
ad6348a12a
Closes #8823 https://github.com/enso-org/enso/assets/6566674/966576ec-6507-401c-98d3-bd71c2ffc6b2 Adds a basic text widget for text literals. ### Important Notes Several known restrictions: - Separators would always be replaced with single quotation marks. All types of separators in Enso are supported though, and they would be correctly escaped if needed. - Logic for widget selection probably needs refinement (works for text literals and `Text` types, but does not work for `Text | Integer`, for example) - **(!)** There is a very annoying issue when the input field suddenly loses focus, closing the editing mode and discarding any changes. Debugging shows that it happens when we receive an engine update (and probably recreate the node component/widget tree (???)). It requires a separate investigation.
237 lines
7.8 KiB
TypeScript
237 lines
7.8 KiB
TypeScript
import test, { expect, type Locator, type Page } from 'playwright/test'
|
|
import * as actions from './actions'
|
|
import { mockMethodCallInfo } from './expressionUpdates'
|
|
import * as locate from './locate'
|
|
|
|
class DropDownLocator {
|
|
readonly dropDown: Locator
|
|
readonly items: Locator
|
|
|
|
constructor(page: Page) {
|
|
this.dropDown = page.locator('.dropdownContainer')
|
|
this.items = this.dropDown.locator('.selectable-item')
|
|
}
|
|
|
|
async expectVisibleWithOptions(page: Page, options: string[]): Promise<void> {
|
|
await expect(this.dropDown).toBeVisible()
|
|
await expect(this.items).toHaveCount(options.length)
|
|
for (const option of options) {
|
|
await expect(
|
|
this.items.filter({ has: page.getByText(option, { exact: true }) }),
|
|
).toBeVisible()
|
|
}
|
|
}
|
|
|
|
async clickOption(page: Page, option: string): Promise<void> {
|
|
await this.items.filter({ has: page.getByText(option) }).click()
|
|
}
|
|
}
|
|
|
|
test('Selection widgets in Data.read node', async ({ page }) => {
|
|
await actions.goToGraph(page)
|
|
await mockMethodCallInfo(page, 'data', {
|
|
methodPointer: {
|
|
module: 'Standard.Base.Data',
|
|
definedOnType: 'Standard.Base.Data',
|
|
name: 'read',
|
|
},
|
|
notAppliedArguments: [0, 1, 2],
|
|
})
|
|
|
|
const dropDown = new DropDownLocator(page)
|
|
|
|
// Check initially visible arguments
|
|
const node = locate.graphNodeByBinding(page, 'data')
|
|
const argumentNames = node.locator('.WidgetArgumentName')
|
|
await expect(argumentNames).toHaveCount(3)
|
|
|
|
// Set value on `on_problems` (static drop-down)
|
|
const onProblemsArg = argumentNames.filter({ has: page.getByText('on_problems') })
|
|
await onProblemsArg.click()
|
|
await dropDown.expectVisibleWithOptions(page, ['Ignore', 'Report Warning', 'Report Error'])
|
|
await dropDown.clickOption(page, 'Report Error')
|
|
await expect(onProblemsArg.locator('.WidgetToken')).toHaveText([
|
|
'Problem_Behavior',
|
|
'.',
|
|
'Report_Error',
|
|
])
|
|
|
|
// Change value on `on_problems`
|
|
await mockMethodCallInfo(page, 'data', {
|
|
methodPointer: {
|
|
module: 'Standard.Base.Data',
|
|
definedOnType: 'Standard.Base.Data',
|
|
name: 'read',
|
|
},
|
|
notAppliedArguments: [0, 1],
|
|
})
|
|
await page.getByText('Report_Error').click()
|
|
await dropDown.expectVisibleWithOptions(page, ['Ignore', 'Report Warning', 'Report Error'])
|
|
await dropDown.clickOption(page, 'Report Warning')
|
|
await expect(onProblemsArg.locator('.WidgetToken')).toHaveText([
|
|
'Problem_Behavior',
|
|
'.',
|
|
'Report_Warning',
|
|
])
|
|
|
|
// Set value on `path` (dynamic config)
|
|
const pathArg = argumentNames.filter({ has: page.getByText('path') })
|
|
await pathArg.click()
|
|
await expect(page.locator('.dropdownContainer')).toBeVisible()
|
|
await dropDown.expectVisibleWithOptions(page, ['File 1', 'File 2'])
|
|
await dropDown.clickOption(page, 'File 2')
|
|
await expect(pathArg.locator('.EnsoTextInputWidget > input')).toHaveValue('"File 2"')
|
|
|
|
// Change value on `path` (dynamic config)
|
|
await mockMethodCallInfo(page, 'data', {
|
|
methodPointer: {
|
|
module: 'Standard.Base.Data',
|
|
definedOnType: 'Standard.Base.Data',
|
|
name: 'read',
|
|
},
|
|
notAppliedArguments: [1],
|
|
})
|
|
await page.getByText('path').click()
|
|
await dropDown.expectVisibleWithOptions(page, ['File 1', 'File 2'])
|
|
await dropDown.clickOption(page, 'File 1')
|
|
await expect(pathArg.locator('.EnsoTextInputWidget > input')).toHaveValue('"File 1"')
|
|
})
|
|
|
|
test('Managing aggregates in `aggregate` node', async ({ page }) => {
|
|
await actions.goToGraph(page)
|
|
await mockMethodCallInfo(page, 'aggregated', {
|
|
methodPointer: {
|
|
module: 'Standard.Table.Data.Table',
|
|
definedOnType: 'Standard.Table.Data.Table.Table',
|
|
name: 'aggregate',
|
|
},
|
|
notAppliedArguments: [1, 2, 3],
|
|
})
|
|
const dropDown = new DropDownLocator(page)
|
|
|
|
// Check initially visible arguments
|
|
const node = locate.graphNodeByBinding(page, 'aggregated')
|
|
const argumentNames = node.locator('.WidgetArgumentName')
|
|
await expect(argumentNames).toHaveCount(3)
|
|
|
|
// Add first aggregate
|
|
const columnsArg = argumentNames.filter({ has: page.getByText('columns') })
|
|
await columnsArg.locator('.add-item').click()
|
|
await expect(columnsArg.locator('.WidgetToken')).toHaveText(['Aggregate_Column', '.', 'Group_By'])
|
|
await mockMethodCallInfo(
|
|
page,
|
|
{
|
|
binding: 'aggregated',
|
|
expr: 'Aggregate_Column.Group_By',
|
|
},
|
|
{
|
|
methodPointer: {
|
|
module: 'Standard.Table.Data.Aggregate_Column',
|
|
definedOnType: 'Standard.Table.Data.Aggregate_Column.Aggregate_Column',
|
|
name: 'Group_By',
|
|
},
|
|
notAppliedArguments: [0, 1],
|
|
},
|
|
)
|
|
|
|
// Change aggregation type
|
|
const firstItem = columnsArg.locator('.item > .WidgetPort > .WidgetSelection')
|
|
await firstItem.click()
|
|
await dropDown.expectVisibleWithOptions(page, ['Group By', 'Count', 'Count Distinct'])
|
|
await dropDown.clickOption(page, 'Count Distinct')
|
|
await expect(columnsArg.locator('.WidgetToken')).toHaveText([
|
|
'Aggregate_Column',
|
|
'.',
|
|
'Count_Distinct',
|
|
])
|
|
await mockMethodCallInfo(
|
|
page,
|
|
{
|
|
binding: 'aggregated',
|
|
expr: 'Aggregate_Column.Count_Distinct',
|
|
},
|
|
{
|
|
methodPointer: {
|
|
module: 'Standard.Table.Data.Aggregate_Column',
|
|
definedOnType: 'Standard.Table.Data.Aggregate_Column.Aggregate_Column',
|
|
name: 'Count_Distinct',
|
|
},
|
|
notAppliedArguments: [0, 1, 2],
|
|
},
|
|
)
|
|
|
|
// Set column
|
|
const columnArg = firstItem.locator('.WidgetSelection').first()
|
|
await columnArg.click()
|
|
await dropDown.expectVisibleWithOptions(page, ['column 1', 'column 2'])
|
|
await dropDown.clickOption(page, 'column 1')
|
|
await expect(columnsArg.locator('.WidgetToken')).toHaveText([
|
|
'Aggregate_Column',
|
|
'.',
|
|
'Count_Distinct',
|
|
])
|
|
await expect(columnsArg.locator('.EnsoTextInputWidget > input')).toHaveValue('"column 1"')
|
|
|
|
// Add another aggregate
|
|
await columnsArg.locator('.add-item').click()
|
|
await expect(columnsArg.locator('.WidgetToken')).toHaveText([
|
|
'Aggregate_Column',
|
|
'.',
|
|
'Count_Distinct',
|
|
'Aggregate_Column',
|
|
'.',
|
|
'Group_By',
|
|
])
|
|
await mockMethodCallInfo(
|
|
page,
|
|
{
|
|
binding: 'aggregated',
|
|
expr: 'Aggregate_Column.Group_By',
|
|
},
|
|
{
|
|
methodPointer: {
|
|
module: 'Standard.Table.Data.Aggregate_Column',
|
|
definedOnType: 'Standard.Table.Data.Aggregate_Column.Aggregate_Column',
|
|
name: 'Group_By',
|
|
},
|
|
notAppliedArguments: [0, 1],
|
|
},
|
|
)
|
|
|
|
// Set new aggregate's column
|
|
const secondItem = columnsArg.locator('.item > .WidgetPort > .WidgetSelection').nth(1)
|
|
const secondColumnArg = secondItem.locator('.WidgetSelection').first()
|
|
await secondColumnArg.click()
|
|
await dropDown.expectVisibleWithOptions(page, ['column 1', 'column 2'])
|
|
await dropDown.clickOption(page, 'column 2')
|
|
await expect(secondItem.locator('.WidgetToken')).toHaveText(['Aggregate_Column', '.', 'Group_By'])
|
|
await expect(secondItem.locator('.EnsoTextInputWidget > input')).toHaveValue('"column 2"')
|
|
|
|
// Switch aggregates
|
|
//TODO[ao] I have no idea how to emulate drag. Simple dragTo does not work (some element seem to capture event).
|
|
// When hovered, the handle becomes available after some time, but still mouse events don't have any effect.
|
|
// I have no time now to investigate this.
|
|
// Once fixed, add also removing element from vector here.
|
|
|
|
// await columnsArg.locator('.item > .handle').nth(1).hover({ force: true })
|
|
// await columnsArg.locator('.item > .handle').nth(1).hover()
|
|
// await page.mouse.down()
|
|
// await columnsArg.locator('.item > .handle').nth(0).hover({ force: true })
|
|
// await columnsArg.locator('.item > .handle').nth(0).hover()
|
|
// await page.mouse.up()
|
|
// await expect(columnsArg.locator('.WidgetToken')).toHaveText([
|
|
// 'Aggregate_Column',
|
|
// '.',
|
|
// 'Group_By',
|
|
// '"',
|
|
// 'column 2',
|
|
// '"',
|
|
// 'Aggregate_Column',
|
|
// '.',
|
|
// 'Count_Distinct',
|
|
// '"',
|
|
// 'column 1',
|
|
// '"',
|
|
// ])
|
|
})
|