Files
iot-dc3/dc3-web/tests/component/things-card-header.test.ts
pnokerandClaude Code 3fb43c4239 feat(web): unify three-terminal control density and close audit defects
Land the v7 three-terminal UX decision: drop the width/pointer-based
44px touch enlargement so one 32px density holds across desktop,
tablet, and mobile, and rebuild entity pages on a responsive record
list (ResponsiveRecordList + EntityMobileCard + per-entity mobile
summaries). Tighten the nginx security headers (CSP frame-ancestors
'none', X-Frame-Options DENY) to match the static e2e server.

Complete the dc3-web audit remediation, including the remaining LOW
items from docs/dc3-web-low-defects-handoff.md: streaming-safe
message loads in the agentic store, mock menu reparent cycle
rejection, paged-list page clamping, fetch/axios mock request
normalization, per-table attribute catalogs, post-flush alarm
watchers, rowKey-agnostic delete state, localized card text
fallbacks, and e2e-server port fail-fast.

Gate: vue-tsc, eslint, vitest 687 passed, responsive e2e 64 passed.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-07 19:33:17 +08:00

62 lines
2.5 KiB
TypeScript

/*
* Copyright 2016-present the IoT DC3 original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {mount} from '@vue/test-utils';
import {describe, expect, it} from 'vitest';
import ThingsCardHeader from '@/components/card/header/ThingsCardHeader.vue';
function mountHeader(props: Record<string, unknown>, slots: Record<string, string> = {}) {
return mount(ThingsCardHeader, {
props: {icon: '/icons/driver.svg', copyLabel: 'Copy ID', ...props},
slots,
});
}
describe('ThingsCardHeader', () => {
it('renders the name and icon, and emits copy-id on name click', async () => {
const wrapper = mountHeader({name: 'Modbus', icon: '/icons/modbus.svg'});
expect(wrapper.find('.things-card-header-name').text()).toBe('Modbus');
expect(wrapper.find('img').attributes('src')).toBe('/icons/modbus.svg');
expect(wrapper.find('img').attributes('alt')).toBe('Modbus');
await wrapper.find('.things-card-header-name').trigger('click');
expect(wrapper.emitted('copy-id')).toHaveLength(1);
});
it('toggles the enable/disable border class based on the enabled prop', () => {
const enabled = mountHeader({name: 'A', enabled: true});
expect(enabled.find('.header-enable').exists()).toBe(true);
expect(enabled.find('.header-disable').exists()).toBe(false);
const disabled = mountHeader({name: 'B', enabled: false});
expect(disabled.find('.header-enable').exists()).toBe(false);
expect(disabled.find('.header-disable').exists()).toBe(true);
});
it('exposes the status slot with a tooltip via statusTitle', () => {
const wrapper = mountHeader(
{name: 'C', statusTitle: 'last seen 5m ago'},
{default: '<span class="status-tag">online</span>'}
);
expect(wrapper.find('.status-tag').text()).toBe('online');
expect(wrapper.find('.things-card-header-status').attributes('title')).toBe('last seen 5m ago');
});
});