// noinspection DuplicatedCode import type { StoryObj } from '@storybook/web-components'; import {expect, userEvent, within} from '@storybook/test'; import {cloneAs, mix, mergeAttr} from'../custom-element/custom-element.js'; type TProps = { title: string; body:string}; type Story = StoryObj; function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } function render(args: TProps) { const {title, body} = args; return `
${ title } ${ body }
`; } const meta = { title: 'attributes' // , tags: ['autodocs'] , render , parameters: { test:{ dangerouslyIgnoreUnhandledErrors: true}} }; export default meta; function html2Element( htmlStr: string) { const n = document.createElement('div'); n.innerHTML = htmlStr; return n.firstElementChild as HTMLElement; } export const CloneAs:Story = { args : {title: 'cloneAs(el,newTag)', body:`

cloneAs() used for conversion of attribute to xsl:param

default_P1 `} , play: async ({canvasElement}) => { const canvas = within(canvasElement); const cmp = async ( tid:string ) => { const t1 = await canvas.findByTestId(tid); const c1 = cloneAs(t1, 'xsl:param'); for( let a of t1.attributes ) { await expect(a.value).toEqual(c1.getAttribute(a.name)); } await expect( c1.textContent ).toEqual(t1.textContent); } await cmp('t1'); await cmp('t2'); await cmp('t3'); }, }; export const Mix:Story = { args : {title: 'mix(to,from)', body:`

mix(to,from) used for attribute collections

`} , play: async () => { await expect( mix({},{a:1,b:'2'})).toEqual({a:1,b:'2'}); }, }; export const MergeAttr:Story = { args : {title: 'mergeAttr( from, to )', body:`

mergeAttr( from, to ) used for attribute collections

`} , play: async () => { const from = html2Element('
'); const to = html2Element('
'); await expect( to).toHaveAttribute('removed'); mergeAttr(from!,to); await expect( to).toHaveAttribute('title','a'); await expect( to).toHaveAttribute('id','b'); await expect( to).toHaveAttribute('readonly'); await expect( to.getAttributeNames().length).toEqual(3); await expect( to).not.toHaveAttribute('removed'); }, }; export const dceExportedAttributes:Story = { args : {title: 'mergeAttr( from, to )', body:`

mergeAttr( from, to ) used for attribute collections

dceExportedAttributes property on target element defines the set of attributes which would not be removed from target element

`} , play: async () => { const from = html2Element('
'); const to = html2Element('
') as (HTMLElement & {dceExportedAttributes:Set}); to.dceExportedAttributes = new Set(['enforced']); to.setAttribute('enforced',"defined by inner component"); await expect( to).toHaveAttribute('enforced'); mergeAttr(from,to); await expect( to).toHaveAttribute('id','b'); await expect( to).toHaveAttribute('readonly'); await expect( to).not.toHaveAttribute('removed'); await expect( to).toHaveAttribute('enforced',"defined by inner component"); }, }; export const dceExportedAttributes_attr:Story = { args : {title: 'mergeAttr( from, to )', body:`

mergeAttr( from, to ) used for attribute collections

dce-exported-attributes attribute on target element defines the space separated list of attributes which would not be removed from target element

`} , play: async () => { const from = html2Element('
'); const to = html2Element('
') as (HTMLElement & {dceExportedAttributes:Set}); to.setAttribute('enforced',"defined by inner component"); await expect( to).toHaveAttribute('enforced'); mergeAttr(from,to); await expect( to).toHaveAttribute('id','b'); await expect( to).toHaveAttribute('readonly'); await expect( to).not.toHaveAttribute('removed'); await expect( to).toHaveAttribute('enforced',"defined by inner component"); }, }; export const AttributeDefaults:Story = { args : {title: 'Attributes definition', body:`

Params needed to declare DCE attributes and track the attributes changes. It also is used by IDE and validation.

`} , play: async ({canvasElement}) => { const canvas = within(canvasElement); expect( await await canvas.findByTestId('p1') ).toHaveTextContent('default_P1' ); expect( await await canvas.findByTestId('p2') ).toHaveTextContent('always_p2' ); expect( await await canvas.findByTestId('p3') ).toHaveTextContent('def_P3' ); }, }; export const AttributesRuntimeChange:Story = { args : {title: 'Attributes runtime change', body:`

Params needed to declare DCE attributes and track the attributes changes. It also be used by IDE and validation.


`} , play: async ({canvasElement}) => { const canvas = within(canvasElement) , code = async (id:string) => await canvas.findByTestId(id); await sleep(20) expect( await code('t1') ).toHaveTextContent('123' ); expect( await code('t2') ).toHaveTextContent('always_p2'); // no overrides due to value is hardcoded expect( await code('t3') ).toHaveTextContent('def_P3' ); const dce2 = window.dce2; dce2.setAttribute('P1',i1.value); await expect(await canvas.findByText('P1')).toBeInTheDocument(); expect( await code('t1') ).toHaveTextContent('P1'); // 4. set p1 in runtime' dce2.setAttribute('p2',i2.value); // await expect(await canvas.findByText('P2')).toBeInTheDocument(); expect( canvas.getByTestId('t2') ).toHaveTextContent('always_p2'); // can not set p2 in runtime dce2.setAttribute('p3',i3.value); await expect(await canvas.findByText('P3')).toBeInTheDocument(); expect( canvas.getByTestId('t3') ).toHaveTextContent('P3'); // set p3 in runtime }, }; export const InstanceAttributes:Story = { args : {title: 'Instance Attributes', body:`

Params needed to declare DCE attributes and track the attributes changes. It also is used by IDE and validation.

| `} , play: async ({canvasElement}) => { const titleText = AttributeDefaults.args!.title as string; const canvas = within(canvasElement) , code = async (id) => (await canvas.findByTestId(id)).textContent.trim(); await sleep(200) expect( await code('p1') ).toEqual('123' ); expect( await code('p2') ).toEqual('always_p2' ); expect( await code('p3') ).toEqual('qwe' ); }, }; export const AttributesPropagationUp:Story = { args : {title: 'Instance Attributes', body:`

Attributes with value(p2) or select(p3) should be propagated to DCE

p1 attribute is not propagated as does not have the value.

`} , play: async ({canvasElement}) => { const canvas = within(canvasElement) , code = async (id:string) => (await canvas.findByTestId(id)).textContent?.trim(); await sleep(20) await expect( await code('t1-p1') ).toEqual('' ); await expect( await code('t1-p2') ).toEqual('DEFAULT VALUE' ); await expect( await code('t1-p3') ).toEqual('' ); const t1 = await canvas.findByTestId('t1'); await expect( t1 ).toHaveAttribute('value','123'); await expect( t1 ).toHaveAttribute('p2','DEFAULT VALUE'); await expect( t1 ).toHaveAttribute('p3',''); await expect( t1 ).not.toHaveAttribute('p1'); await expect( await code('t2-p1') ).toEqual('P1' ); await expect( await code('t2-p2') ).toEqual('123' ); await expect( await code('t2-p3') ).toEqual('' ); const t2 = await canvas.findByTestId('t2'); await expect( t2 ).toHaveAttribute('p1','P1'); await expect( t2 ).toHaveAttribute('p2','123'); await expect( t2 ).toHaveAttribute('p3',''); await expect( await code('t3-p1') ).toEqual('' ); await expect( await code('t3-p2') ).toEqual('DEFAULT VALUE' ); await expect( await code('t3-p3') ).toEqual('' ); const t3 = await canvas.findByTestId('t3'); await expect( t1 ).not.toHaveAttribute('p1'); await expect( t3 ).toHaveAttribute('p2','DEFAULT VALUE'); await expect( t3 ).toHaveAttribute('p3',''); t3.querySelector('input')?.focus(); await userEvent.keyboard('DCE'); await canvas.findByText('//from-input: DCE') await expect( t3 ).toHaveAttribute('p3','DCE'); }, }; //#region unit tests /* istanbul ignore else -- @preserve */ if( 'test' === import.meta.env.MODE && !import.meta.url.includes('skiptest') ) { const mod = await import('./attributes.test.stories.ts?skiptest'); const { testStoryBook } = await import('./testStoryBook') const { describe } = await import('vitest') describe(meta.title, () => testStoryBook( mod, meta ) ); } //#endregion