@furystack/shades-common-components
Version:
Common UI components for FuryStack Shades
770 lines • 38.4 kB
JavaScript
import { createInjector } from '@furystack/inject';
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades';
import { usingAsync } from '@furystack/utils';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { LayoutService } from '../../services/layout-service.js';
import { PageLayout } from './index.js';
describe('PageLayout component', () => {
beforeEach(() => {
document.body.innerHTML = '<div id="root"></div>';
});
afterEach(() => {
document.body.innerHTML = '';
});
const renderPageLayout = async (options = {}) => {
const injector = createInjector();
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: options.appBar, drawer: options.drawer }, options.children ?? createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
return {
injector,
pageLayout,
layoutService: pageLayout.injector.get(LayoutService),
[Symbol.asyncDispose]: () => injector[Symbol.asyncDispose](),
};
};
describe('rendering', () => {
it('should render the shade-page-layout custom element', async () => {
await usingAsync(await renderPageLayout(), async ({ pageLayout }) => {
expect(pageLayout).not.toBeNull();
expect(pageLayout.tagName.toLowerCase()).toBe('shade-page-layout');
});
});
it('should render children in content area', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, null,
createComponent("div", { id: "test-content" }, "Test Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).toContain('page-layout-content');
});
});
});
describe('positioning', () => {
it('should have fixed positioning', async () => {
await usingAsync(await renderPageLayout(), async ({ pageLayout }) => {
const computedStyle = window.getComputedStyle(pageLayout);
expect(computedStyle.position).toBe('fixed');
});
});
it('should have full width', async () => {
await usingAsync(await renderPageLayout(), async ({ pageLayout }) => {
const computedStyle = window.getComputedStyle(pageLayout);
expect(computedStyle.width).toBe('100%');
});
});
it('should have full height', async () => {
await usingAsync(await renderPageLayout(), async ({ pageLayout }) => {
const computedStyle = window.getComputedStyle(pageLayout);
expect(computedStyle.height).toBe('100%');
});
});
});
describe('AppBar', () => {
it('should render AppBar when configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: {
variant: 'permanent',
component: createComponent("div", { id: "my-appbar" }, "AppBar Content"),
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).toContain('page-layout-appbar');
expect(document.body.innerHTML).toContain('my-appbar');
});
});
it('should not render AppBar when not configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, null,
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).not.toContain('page-layout-appbar');
});
});
it('should use custom AppBar height', async () => {
await usingAsync(await renderPageLayout({
appBar: {
variant: 'permanent',
height: '64px',
component: createComponent("div", null, "AppBar"),
},
}), async ({ layoutService }) => {
expect(layoutService.appBarHeight.getValue()).toBe('64px');
});
});
it('should use default AppBar height when not specified', async () => {
await usingAsync(await renderPageLayout({
appBar: {
variant: 'permanent',
component: createComponent("div", null, "AppBar"),
},
}), async ({ layoutService }) => {
expect(layoutService.appBarHeight.getValue()).toBe('48px');
});
});
it('should add appbar-auto-hide class to host for auto-hide variant', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: {
variant: 'auto-hide',
component: createComponent("div", null, "AppBar"),
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-appbar-auto-hide')).toBe(true);
});
});
it('should not add appbar-auto-hide class to host for permanent variant', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: {
variant: 'permanent',
component: createComponent("div", null, "AppBar"),
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-appbar-auto-hide')).toBe(false);
});
});
it('should not have appbar-visible class initially for auto-hide variant (starts hidden)', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: {
variant: 'auto-hide',
component: createComponent("div", null, "AppBar"),
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
// Auto-hide appbars should start hidden (no data-appbar-visible attribute)
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-appbar-visible')).toBe(false);
});
});
});
describe('Left Drawer', () => {
it('should render left drawer when configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { drawer: {
left: {
variant: 'permanent',
component: createComponent("div", { id: "left-drawer" }, "Left Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).toContain('page-layout-drawer-left');
expect(document.body.innerHTML).toContain('left-drawer');
});
});
it('should not render left drawer when not configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, null,
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).not.toContain('page-layout-drawer-left');
});
});
it('should initialize permanent drawer as open', async () => {
await usingAsync(await renderPageLayout({
drawer: {
left: {
variant: 'permanent',
component: createComponent("div", null, "Left Drawer"),
},
},
}), async ({ layoutService }) => {
expect(layoutService.drawerState.getValue().left?.open).toBe(true);
});
});
it('should initialize collapsible drawer as open by default', async () => {
await usingAsync(await renderPageLayout({
drawer: {
left: {
variant: 'collapsible',
component: createComponent("div", null, "Left Drawer"),
},
},
}), async ({ layoutService }) => {
expect(layoutService.drawerState.getValue().left?.open).toBe(true);
});
});
it('should initialize collapsible drawer as closed when defaultOpen is false', async () => {
await usingAsync(await renderPageLayout({
drawer: {
left: {
variant: 'collapsible',
defaultOpen: false,
component: createComponent("div", null, "Left Drawer"),
},
},
}), async ({ layoutService }) => {
expect(layoutService.drawerState.getValue().left?.open).toBe(false);
});
});
it('should use custom drawer width', async () => {
await usingAsync(await renderPageLayout({
drawer: {
left: {
variant: 'permanent',
width: '300px',
component: createComponent("div", null, "Left Drawer"),
},
},
}), async ({ layoutService }) => {
expect(layoutService.drawerState.getValue().left?.width).toBe('300px');
});
});
it('should use default drawer width when not specified', async () => {
await usingAsync(await renderPageLayout({
drawer: {
left: {
variant: 'permanent',
component: createComponent("div", null, "Left Drawer"),
},
},
}), async ({ layoutService }) => {
expect(layoutService.drawerState.getValue().left?.width).toBe('240px');
});
});
it('should add drawer-left-closed class to host when drawer is closed', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { drawer: {
left: {
variant: 'collapsible',
defaultOpen: false,
component: createComponent("div", null, "Left Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-drawer-left-closed')).toBe(true);
});
});
});
describe('Right Drawer', () => {
it('should render right drawer when configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { drawer: {
right: {
variant: 'permanent',
component: createComponent("div", { id: "right-drawer" }, "Right Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).toContain('page-layout-drawer-right');
expect(document.body.innerHTML).toContain('right-drawer');
});
});
it('should not render right drawer when not configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, null,
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).not.toContain('page-layout-drawer-right');
});
});
it('should initialize right drawer state correctly', async () => {
await usingAsync(await renderPageLayout({
drawer: {
right: {
variant: 'permanent',
width: '200px',
component: createComponent("div", null, "Right Drawer"),
},
},
}), async ({ layoutService }) => {
expect(layoutService.drawerState.getValue().right).toEqual({
open: true,
width: '200px',
variant: 'permanent',
});
});
});
});
describe('Both Drawers', () => {
it('should render both drawers when configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { drawer: {
left: {
variant: 'permanent',
component: createComponent("div", { id: "left-drawer" }, "Left Drawer"),
},
right: {
variant: 'permanent',
component: createComponent("div", { id: "right-drawer" }, "Right Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).toContain('page-layout-drawer-left');
expect(document.body.innerHTML).toContain('page-layout-drawer-right');
});
});
it('should initialize both drawer states correctly', async () => {
await usingAsync(await renderPageLayout({
drawer: {
left: {
variant: 'permanent',
width: '240px',
component: createComponent("div", null, "Left Drawer"),
},
right: {
variant: 'collapsible',
width: '200px',
defaultOpen: false,
component: createComponent("div", null, "Right Drawer"),
},
},
}), async ({ layoutService }) => {
expect(layoutService.drawerState.getValue()).toEqual({
left: { open: true, width: '240px', variant: 'permanent' },
right: { open: false, width: '200px', variant: 'collapsible' },
});
});
});
});
describe('Temporary Drawer Backdrop', () => {
it('should render backdrop element', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { drawer: {
left: {
variant: 'temporary',
component: createComponent("div", null, "Temporary Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).toContain('page-layout-drawer-backdrop');
});
});
it('should add backdrop-visible class to host when temporary drawer is open', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { drawer: {
left: {
variant: 'temporary',
defaultOpen: true,
component: createComponent("div", null, "Temporary Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-backdrop-visible')).toBe(true);
});
});
it('should close temporary drawer when backdrop is clicked', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { drawer: {
left: {
variant: 'temporary',
defaultOpen: true,
component: createComponent("div", null, "Temporary Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-drawer-left-closed')).toBe(false);
const backdrop = document.querySelector('.page-layout-drawer-backdrop');
backdrop.click();
await flushUpdates();
expect(pageLayout?.hasAttribute('data-drawer-left-closed')).toBe(true);
});
});
});
describe('Content Area', () => {
it('should render content area', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, null,
createComponent("div", null, "Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).toContain('page-layout-content');
});
});
it('should set data-nav-section="content" on the content area for spatial navigation scoping', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, null,
createComponent("div", null, "Content"))),
});
await flushUpdates();
const contentArea = document.querySelector('.page-layout-content');
expect(contentArea?.getAttribute('data-nav-section')).toBe('content');
});
});
it('should set CSS variable for zero paddingTop when no AppBar is configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, null,
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
// AppBar height is 0 when not configured, so contentPaddingTop = calc(0px + 0px)
expect(pageLayout.style.getPropertyValue('--layout-appbar-height')).toBe('0px');
expect(pageLayout.style.getPropertyValue('--layout-content-padding-top')).toBe('calc(0px + 0px)');
});
});
it('should set CSS variable for paddingTop equal to AppBar height when AppBar is configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: {
variant: 'permanent',
component: createComponent("div", null, "AppBar"),
height: '64px',
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
// Content padding top CSS variable should be calculated from appBarHeight + topGap
expect(pageLayout.style.getPropertyValue('--layout-appbar-height')).toBe('64px');
expect(pageLayout.style.getPropertyValue('--layout-content-padding-top')).toBe('calc(64px + 0px)');
});
});
it('should set CSS variable for topGap when configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: {
variant: 'permanent',
component: createComponent("div", null, "AppBar"),
height: '48px',
}, topGap: "16px" },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout.style.getPropertyValue('--layout-top-gap')).toBe('16px');
expect(pageLayout.style.getPropertyValue('--layout-content-padding-top')).toBe('calc(48px + 16px)');
});
});
it('should set CSS variable for sideGap when configured', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { sideGap: "24px" },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout.style.getPropertyValue('--layout-side-gap')).toBe('24px');
});
});
});
describe('LayoutService Integration', () => {
it('should update AppBar height to 0 when no AppBar is configured', async () => {
await usingAsync(await renderPageLayout(), async ({ layoutService }) => {
expect(layoutService.appBarHeight.getValue()).toBe('0px');
});
});
it('should respond to drawer state changes from LayoutService', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { drawer: {
left: {
variant: 'collapsible',
component: createComponent("div", null, "Left Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
const layoutService = pageLayout.injector.get(LayoutService);
// Initially open
expect(pageLayout.hasAttribute('data-drawer-left-closed')).toBe(false);
// Close via LayoutService
layoutService.setDrawerOpen('left', false);
await flushUpdates();
expect(pageLayout.hasAttribute('data-drawer-left-closed')).toBe(true);
});
});
it('should respond to appBarVisible changes for auto-hide variant', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: {
variant: 'auto-hide',
component: createComponent("div", null, "AppBar"),
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
const layoutService = pageLayout.injector.get(LayoutService);
// Initially hidden for auto-hide variant
expect(pageLayout.hasAttribute('data-appbar-visible')).toBe(false);
expect(layoutService.appBarVisible.getValue()).toBe(false);
// Setting appBarVisible to true should persist across re-renders
layoutService.appBarVisible.setValue(true);
await flushUpdates();
expect(layoutService.appBarVisible.getValue()).toBe(true);
expect(pageLayout.hasAttribute('data-appbar-visible')).toBe(true);
});
});
});
describe('Full Layout', () => {
it('should render complete layout with AppBar and both drawers', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { appBar: {
variant: 'permanent',
height: '64px',
component: createComponent("div", { id: "appbar" }, "AppBar"),
}, drawer: {
left: {
variant: 'collapsible',
width: '240px',
component: createComponent("div", { id: "left-drawer" }, "Left Sidebar"),
},
right: {
variant: 'permanent',
width: '200px',
component: createComponent("div", { id: "right-drawer" }, "Right Panel"),
},
} },
createComponent("div", { id: "main-content" }, "Main Content"))),
});
await flushUpdates();
expect(document.body.innerHTML).toContain('page-layout-appbar');
expect(document.body.innerHTML).toContain('page-layout-drawer-left');
expect(document.body.innerHTML).toContain('page-layout-drawer-right');
expect(document.body.innerHTML).toContain('page-layout-content');
const pageLayout = document.querySelector('shade-page-layout');
const layoutService = pageLayout.injector.get(LayoutService);
expect(layoutService.appBarHeight.getValue()).toBe('64px');
expect(layoutService.drawerState.getValue()).toEqual({
left: { open: true, width: '240px', variant: 'collapsible' },
right: { open: true, width: '200px', variant: 'permanent' },
});
});
});
});
describe('Contained Mode', () => {
it('should set data-contained attribute on host when contained is true', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { contained: true },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-contained')).toBe(true);
});
});
it('should not set data-contained attribute when contained is not set', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, null,
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-contained')).toBe(false);
});
});
it('should have absolute positioning when contained', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { contained: true },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
const computedStyle = window.getComputedStyle(pageLayout);
expect(computedStyle.position).toBe('absolute');
});
});
it('should work with AppBar and drawers in contained mode', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { contained: true, appBar: {
variant: 'permanent',
component: createComponent("div", null, "AppBar"),
}, drawer: {
left: {
variant: 'collapsible',
component: createComponent("div", null, "Left Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout.hasAttribute('data-contained')).toBe(true);
expect(document.body.innerHTML).toContain('page-layout-appbar');
expect(document.body.innerHTML).toContain('page-layout-drawer-left');
expect(document.body.innerHTML).toContain('page-layout-content');
const layoutService = pageLayout.injector.get(LayoutService);
expect(layoutService.drawerState.getValue().left?.open).toBe(true);
});
});
it('should support drawer toggle in contained mode', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { contained: true, drawer: {
left: {
variant: 'collapsible',
component: createComponent("div", null, "Left Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
const layoutService = pageLayout.injector.get(LayoutService);
expect(pageLayout.hasAttribute('data-drawer-left-closed')).toBe(false);
layoutService.setDrawerOpen('left', false);
await flushUpdates();
expect(pageLayout.hasAttribute('data-drawer-left-closed')).toBe(true);
});
});
it('should support temporary drawer backdrop click in contained mode', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: (createComponent(PageLayout, { contained: true, drawer: {
left: {
variant: 'temporary',
defaultOpen: true,
component: createComponent("div", null, "Temporary Drawer"),
},
} },
createComponent("div", null, "Content"))),
});
await flushUpdates();
const pageLayout = document.querySelector('shade-page-layout');
expect(pageLayout?.hasAttribute('data-backdrop-visible')).toBe(true);
const backdrop = document.querySelector('.page-layout-drawer-backdrop');
backdrop.click();
await flushUpdates();
expect(pageLayout?.hasAttribute('data-drawer-left-closed')).toBe(true);
});
});
});
});
//# sourceMappingURL=index.spec.js.map