@carbon/ibm-products-web-components
Version:
Carbon for IBM Products Web Components
361 lines (358 loc) • 15.6 kB
JavaScript
/**
* Copyright IBM Corp. 2024
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { vi, describe, it, expect } from 'vitest';
import { fixture, html } from '@open-wc/testing';
import Bee32 from '@carbon/web-components/es/icons/bee/32.js';
import { prefix, carbonPrefix } from '../../globals/settings.js';
import './page-header.js';
import './page-header-breadcrumb.js';
import './page-header-content.js';
import './page-header-content-text.js';
import './page-header-hero-image.js';
import './page-header-tabs.js';
import './page-header-title-breadcrumb.js';
import './page-header-scroller.js';
/**
* Copyright IBM Corp. 2025
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
const IntersectionObserverMock = vi.fn(() => ({
disconnect: vi.fn(),
observe: vi.fn(),
unobserve: vi.fn(),
}));
vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);
describe('c4p-page-header', function () {
it('should find custom css properties to initialize sticky positioning', async () => {
const pageHeader = await fixture(html `<c4p-page-header>
<c4p-page-header-breadcrumb>
<cds-breadcrumb>
<cds-breadcrumb-item href="/#">Breadcrumb 1</cds-breadcrumb-item>
<cds-breadcrumb-item href="#">Breadcrumb 2</cds-breadcrumb-item>
</cds-breadcrumb>
</c4p-page-header-breadcrumb>
<c4p-page-header-content title="Page header content title">
</c4p-page-header-content>
</c4p-page-header>`);
await pageHeader.updateComplete;
await new Promise((resolve) => setTimeout(resolve, 0));
const contentHeight = getComputedStyle(pageHeader).getPropertyValue(`--${prefix}-page-header-header-top`);
const breadcrumbPosition = getComputedStyle(pageHeader).getPropertyValue(`--${prefix}-page-header-breadcrumb-top`);
expect(parseFloat(contentHeight)).toBeTypeOf('number');
expect(parseFloat(breadcrumbPosition)).toBeTypeOf('number');
});
describe('c4p-page-header-scroller', () => {
it('should collapse the page header/scroll', async () => {
var _a, _b;
const pageHeader = await fixture(html `<main style="height: 200vh;">
<c4p-page-header>
<c4p-page-header-breadcrumb>
<cds-breadcrumb>
<cds-breadcrumb-item href="/#"
>Breadcrumb 1</cds-breadcrumb-item
>
<cds-breadcrumb-item href="#">Breadcrumb 2</cds-breadcrumb-item>
</cds-breadcrumb>
</c4p-page-header-breadcrumb>
<c4p-page-header-content title="Page header content title">
</c4p-page-header-content>
<c4p-page-header-tabs>
<c4p-page-header-scroller slot="scroller">
</c4p-page-header-scroller>
<cds-tabs value="tab-1">
<cds-tab id="tab-1" target="tab-panel-1" value="tab-1"
>Tab 1</cds-tab
>
<cds-tab id="tab-2" target="tab-panel-2" value="tab-2"
>Tab 2</cds-tab
>
<cds-tab id="tab-3" target="tab-panel-3" value="tab-3"
>Tab 3</cds-tab
>
<cds-tab id="tab-4" target="tab-panel-4" value="tab-4"
>Tab 4</cds-tab
>
<cds-tab id="tab-5" target="tab-panel-5" value="tab-5"
>Tab 5</cds-tab
>
<cds-tab id="tab-6" target="tab-panel-6" value="tab-6"
>Tab 6</cds-tab
>
<cds-tab id="tab-7" target="tab-panel-7" value="tab-7"
>Tab 7</cds-tab
>
</cds-tabs>
</c4p-page-header-tabs>
</c4p-page-header>
<div class="tabs-demo">
<div
id="tab-panel-1"
role="tabpanel"
aria-labelledby="tab-1"
hidden
>
Tab Panel 1
</div>
<div
id="tab-panel-2"
role="tabpanel"
aria-labelledby="tab-2"
hidden
>
Tab Panel 2
</div>
<div
id="tab-panel-3"
role="tabpanel"
aria-labelledby="tab-3"
hidden
>
Tab Panel 3
</div>
<div
id="tab-panel-4"
role="tabpanel"
aria-labelledby="tab-4"
hidden
>
Tab Panel 4
</div>
<div
id="tab-panel-5"
role="tabpanel"
aria-labelledby="tab-5"
hidden
>
Tab Panel 5
</div>
<div
id="tab-panel-6"
role="tabpanel"
aria-labelledby="tab-6"
hidden
>
Tab Panel 6
</div>
<div
id="tab-panel-7"
role="tabpanel"
aria-labelledby="tab-7"
hidden
>
Tab Panel 7
</div>
</div>
</main>`);
await pageHeader.updateComplete;
await new Promise((resolve) => setTimeout(resolve, 0));
const scrollerButton = pageHeader.querySelector(`${prefix}-page-header-scroller`);
const iconButton = (_a = scrollerButton === null || scrollerButton === void 0 ? void 0 : scrollerButton.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(`${carbonPrefix}-icon-button`);
expect(scrollerButton).toBeDefined();
expect((_b = iconButton === null || iconButton === void 0 ? void 0 : iconButton.textContent) === null || _b === void 0 ? void 0 : _b.trim()).toBe('Collapse');
});
});
describe('c4p-page-header-breadcrumb', () => {
it('should place className on the outermost element', async () => {
const el = await fixture(html `<c4p-page-header-breadcrumb
class="custom-class"
></c4p-page-header-breadcrumb>`);
expect(el.getAttribute('class')).to.equal('custom-class');
});
it('should render breadcrumb items', async () => {
const el = await fixture(html `
<c4p-page-header-breadcrumb>
<cds-breadcrumb>
<cds-breadcrumb-item href="/#">Breadcrumb 1</cds-breadcrumb-item>
<cds-breadcrumb-item href="#">Breadcrumb 2</cds-breadcrumb-item>
</cds-breadcrumb>
</c4p-page-header-breadcrumb>
`);
await el.updateComplete;
const breadcrumbItems = el.querySelectorAll('cds-breadcrumb-item');
expect(breadcrumbItems.length).to.equal(2);
});
it('should render title breadcrumb item', async () => {
const el = await fixture(html `
<c4p-page-header-breadcrumb>
<cds-breadcrumb>
<cds-breadcrumb-item href="/#">Breadcrumb 1</cds-breadcrumb-item>
<cds-breadcrumb-item href="#">Breadcrumb 2</cds-breadcrumb-item>
<c4p-page-header-title-breadcrumb>
Virtual Machine DAL
</c4p-page-header-title-breadcrumb>
</cds-breadcrumb>
</c4p-page-header-breadcrumb>
`);
await el.updateComplete;
const titleBreadcrumb = el.querySelectorAll('c4p-page-header-title-breadcrumb');
expect(titleBreadcrumb).to.exist;
});
it('should render content actions', async () => {
const el = await fixture(html `
<c4p-page-header-breadcrumb>
<div slot="content-actions">
<button class="content-action-item">Button</button>
</div>
<cds-breadcrumb>
<cds-breadcrumb-item href="/#">Breadcrumb 1</cds-breadcrumb-item>
<cds-breadcrumb-item href="#">Breadcrumb 2</cds-breadcrumb-item>
</cds-breadcrumb>
</c4p-page-header-breadcrumb>
`);
await el.updateComplete;
const elem = el.querySelector('.content-action-item');
expect(elem).to.exist;
});
it('should render page actions', async () => {
const el = await fixture(html `
<c4p-page-header-breadcrumb>
<div slot="page-actions">
<button class="page-action-item">Button</button>
</div>
<cds-breadcrumb>
<cds-breadcrumb-item href="/#">Breadcrumb 1</cds-breadcrumb-item>
<cds-breadcrumb-item href="#">Breadcrumb 2</cds-breadcrumb-item>
</cds-breadcrumb>
</c4p-page-header-breadcrumb>
`);
await el.updateComplete;
const elem = el.querySelector('.page-action-item');
expect(elem).to.exist;
});
});
describe('c4p-page-header-content', () => {
it('should render a title', async () => {
var _a, _b;
const el = await fixture(html `
<c4p-page-header>
<c4p-page-header-content title="Page header content title">
</c4p-page-header-content>
</c4p-page-header>
`);
const content = el.querySelector(`c4p-page-header-content`);
const title = (_a = content === null || content === void 0 ? void 0 : content.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.c4p--page-header__content__title');
expect(title).to.exist;
expect((_b = title === null || title === void 0 ? void 0 : title.textContent) === null || _b === void 0 ? void 0 : _b.trim()).toBe('Page header content title');
});
it('should render an icon', async () => {
var _a;
const el = await fixture(html `
<c4p-page-header>
<c4p-page-header-content title="Page header content title">
${Bee32({ slot: 'icon' })}
</c4p-page-header-content>
</c4p-page-header>
`);
await el.updateComplete;
const content = el.querySelector('c4p-page-header-content');
const slot = (_a = content === null || content === void 0 ? void 0 : content.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('slot[name="icon"]');
const assigned = slot.assignedNodes({ flatten: true });
const icon = assigned.find((node) => node.nodeType === Node.ELEMENT_NODE &&
node.tagName.toLowerCase() === 'svg');
expect(icon).to.exist;
});
it('should render children', async () => {
const el = await fixture(html `
<c4p-page-header>
<c4p-page-header-content title="Page header content title">
<c4p-page-header-content-text>
Content text
</c4p-page-header-content-text>
</c4p-page-header-content>
</c4p-page-header>
`);
const inner = el.querySelector('c4p-page-header-content-text');
expect(inner === null || inner === void 0 ? void 0 : inner.textContent).to.include('Content text');
});
it('should render contextual actions', async () => {
var _a;
const el = await fixture(html `
<c4p-page-header>
<c4p-page-header-content title="Page header content title">
<div slot="contextual-actions">
<div>action 1</div>
<div>action 2</div>
<div>action 3</div>
</div>
<c4p-page-header-content-text>
Content text
</c4p-page-header-content-text>
</c4p-page-header-content>
</c4p-page-header>
`);
const content = el.querySelector('c4p-page-header-content');
const slot = (_a = content === null || content === void 0 ? void 0 : content.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('slot[name="contextual-actions"]');
const assigned = slot === null || slot === void 0 ? void 0 : slot.assignedNodes({ flatten: true });
const actions = assigned[0].querySelectorAll('div');
expect(actions.length).to.equal(3);
expect(actions[0].textContent).to.include('action 1');
expect(actions[1].textContent).to.include('action 2');
expect(actions[2].textContent).to.include('action 3');
});
it('should render page actions', async () => {
var _a;
const el = await fixture(html `
<c4p-page-header>
<c4p-page-header-content title="Page header content title">
<button slot="page-actions">page actions</button>
<c4p-page-header-content-text>
Content text
</c4p-page-header-content-text>
</c4p-page-header-content>
</c4p-page-header>
`);
const content = el.querySelector('c4p-page-header-content');
const slot = (_a = content === null || content === void 0 ? void 0 : content.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('slot[name="page-actions"]');
const assigned = slot.assignedNodes({ flatten: true });
const button = assigned.find((node) => node.nodeType === Node.ELEMENT_NODE &&
node.tagName.toLowerCase() === 'button');
expect(button).to.exist;
expect(button === null || button === void 0 ? void 0 : button.textContent).to.include('page actions');
});
});
describe('c4p-page-header-tabs', () => {
it('should render tabs', async () => {
const el = await fixture(html ` <c4p-page-header-tabs>
<cds-tabs value="tab-1">
<cds-tab id="tab-1" target="tab-panel-1" value="tab-1"
>Tab 1</cds-tab
>
<cds-tab id="tab-2" target="tab-panel-2" value="tab-2"
>Tab 2</cds-tab
>
</cds-tabs>
</c4p-page-header-tabs>`);
const tabs = el.querySelector('cds-tabs');
expect(tabs).to.exist;
await tabs.updateComplete;
const tab = tabs.querySelectorAll('cds-tab');
expect(tab.length).to.equal(2);
expect(tab[0].textContent).to.include('Tab 1');
expect(tab[1].textContent).to.include('Tab 2');
});
it('should render tags', async () => {
var _a;
const el = await fixture(html ` <c4p-page-header-tabs>
<div slot="tags">
<cds-tag>Tag 1</cds-tag>
<cds-tag>Tag 2</cds-tag>
</div>
</c4p-page-header-tabs>`);
const slot = (_a = el === null || el === void 0 ? void 0 : el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('slot[name="tags"]');
const assigned = slot === null || slot === void 0 ? void 0 : slot.assignedNodes({ flatten: true });
const wrapper = assigned.find((node) => node.nodeType === Node.ELEMENT_NODE &&
node.tagName.toLowerCase() === 'div');
const tags = wrapper === null || wrapper === void 0 ? void 0 : wrapper.querySelectorAll('cds-tag');
expect(tags.length).to.equal(2);
expect(tags[0].textContent).to.include('Tag 1');
expect(tags[1].textContent).to.include('Tag 2');
});
});
});
//# sourceMappingURL=page-header.test.js.map