feat(ui): AttrCombobox declare vs. consume semantics
Attr-string fields in the Custom Modifier Editor now differentiate between declare-sites (seed-attribute.attr) and consume-sites (add-to-attribute.attr, multiply-attribute.attr, add-aura.targetAttr, absorb-damage-with-attribute.attr): - Consume-sites hide the illustrative 'User-defined examples' group (ArmorPlates/BloodStacks/ManaPool) because those names are fiction unless something seeds them. - Consume-sites surface a new 'Seeded in this descriptor' group populated from seed-attribute primitives elsewhere in the current tree (including inside trigger children via childPrimitives). - Badge states: emerald 'seeded' when the typed value matches an in-tree seed; red 'not seeded' when it's a non-schema name with no backing seed; amber 'user-defined' only in declare-mode for off-catalog names. Declare-mode behaviour is unchanged — inventing ShieldCharges there still works without warnings.
This commit is contained in:
parent
934db775f9
commit
8605a22530
5 changed files with 349 additions and 25 deletions
|
|
@ -1368,11 +1368,94 @@ test.describe('T29 — Custom modifier DSL e2e', () => {
|
|||
await page.getByTestId('attr-combobox-option-Hp').first().click();
|
||||
await expect(input).toHaveValue('Hp');
|
||||
|
||||
// seed-attribute is a declare-site, so the illustrative examples
|
||||
// (ArmorPlates, BloodStacks...) SHOULD be present.
|
||||
await input.click();
|
||||
await expect(
|
||||
page.getByTestId('attr-combobox-option-ArmorPlates'),
|
||||
).toBeVisible();
|
||||
|
||||
// Type a user-defined attr name — badge appears, dropdown filters down.
|
||||
await input.fill('MyStacks');
|
||||
await expect(combobox).toContainText('user-defined');
|
||||
});
|
||||
|
||||
test('AttrCombobox consume-mode (add-aura.targetAttr) hides user-defined examples and warns on unseeded names', async ({
|
||||
page,
|
||||
}) => {
|
||||
await freshLobby(page);
|
||||
await openProfileEditor(page);
|
||||
await openCustomModifierEditor(page);
|
||||
|
||||
// Add an add-aura primitive — its targetAttr field is a consume-site.
|
||||
await page.getByTestId('custom-primitive-palette-add-aura').click();
|
||||
await page.getByTestId('custom-primitive-node-0').click();
|
||||
|
||||
const input = page.getByTestId('primitive-add-aura-targetAttr-input');
|
||||
await input.click();
|
||||
const dropdown = page.getByTestId('primitive-add-aura-targetAttr-dropdown');
|
||||
await expect(dropdown).toBeVisible();
|
||||
|
||||
// Illustrative "User-defined examples" group should NOT appear in
|
||||
// consume-mode — those names (ArmorPlates, BloodStacks, ManaPool)
|
||||
// are fiction unless a seed-attribute declares them.
|
||||
await expect(dropdown).not.toContainText('User-defined examples');
|
||||
await expect(
|
||||
page.getByTestId('attr-combobox-option-ArmorPlates'),
|
||||
).toHaveCount(0);
|
||||
|
||||
// Typing an unseeded attr raises the red "not seeded" badge.
|
||||
await input.fill('MyGhostAttr');
|
||||
const badge = page.getByTestId('primitive-add-aura-targetAttr-badge');
|
||||
await expect(badge).toHaveText('not seeded');
|
||||
});
|
||||
|
||||
test('AttrCombobox consume-mode surfaces attrs seeded by other primitives in the same descriptor', async ({
|
||||
page,
|
||||
}) => {
|
||||
await freshLobby(page);
|
||||
await openProfileEditor(page);
|
||||
await openCustomModifierEditor(page);
|
||||
|
||||
// 1. Add a seed-attribute primitive that declares ShieldCharges=3.
|
||||
await page.getByTestId('custom-primitive-palette-seed-attribute').click();
|
||||
await page.getByTestId('custom-primitive-node-0').click();
|
||||
const seedAttrInput = page.getByTestId('primitive-seed-attribute-attr-input');
|
||||
await seedAttrInput.fill('ShieldCharges');
|
||||
// Blur the input so the dropdown closes — the open dropdown is
|
||||
// absolutely positioned and would intercept the next palette click.
|
||||
await seedAttrInput.blur();
|
||||
|
||||
// 2. Add an absorb-damage-with-attribute primitive. Its attr field
|
||||
// is a consume-site and should now offer ShieldCharges under
|
||||
// a "Seeded in this descriptor" group.
|
||||
await page
|
||||
.getByTestId('custom-primitive-palette-absorb-damage-with-attribute')
|
||||
.click();
|
||||
await page.getByTestId('custom-primitive-node-1').click();
|
||||
|
||||
const absorbInput = page.getByTestId(
|
||||
'primitive-absorb-damage-with-attribute-attr-input',
|
||||
);
|
||||
await absorbInput.click();
|
||||
const dropdown = page.getByTestId(
|
||||
'primitive-absorb-damage-with-attribute-attr-dropdown',
|
||||
);
|
||||
await expect(dropdown).toBeVisible();
|
||||
await expect(dropdown).toContainText('Seeded in this descriptor');
|
||||
await expect(
|
||||
page.getByTestId('attr-combobox-option-ShieldCharges'),
|
||||
).toBeVisible();
|
||||
|
||||
// Picking it commits the value and badge shows emerald "seeded".
|
||||
await page.getByTestId('attr-combobox-option-ShieldCharges').click();
|
||||
await expect(absorbInput).toHaveValue('ShieldCharges');
|
||||
const absorbBadge = page.getByTestId(
|
||||
'primitive-absorb-damage-with-attribute-attr-badge',
|
||||
);
|
||||
await expect(absorbBadge).toHaveText('seeded');
|
||||
});
|
||||
|
||||
test('Templates picker loads a recipe into the editor', async ({ page }) => {
|
||||
await freshLobby(page);
|
||||
await openProfileEditor(page);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue