import { describe, expect, it } from 'vitest';
import { readAttributesAsDataset, readForwardedHostAttributes } from './element-helpers';

describe('readAttributesAsDataset', () => {
  it('指定したケバブケース属性名を camelCase キーに変換して読み取る', () => {
    const el = document.createElement('div');
    el.setAttribute('target', '.js-target');
    el.setAttribute('default-value', 'foo,bar');
    el.setAttribute('menu-portal-target', '#portal');

    const result = readAttributesAsDataset(el, ['target', 'default-value', 'menu-portal-target']);

    expect(result).toEqual({
      target: '.js-target',
      defaultValue: 'foo,bar',
      menuPortalTarget: '#portal',
    });
  });

  it('存在しない属性はキー自体を省略する（HTMLElement.dataset の欠損時と同じ挙動）', () => {
    const el = document.createElement('div');
    el.setAttribute('target', '.js-target');

    const result = readAttributesAsDataset(el, ['target', 'default-value']);

    expect(result).toEqual({ target: '.js-target' });
    expect('defaultValue' in result).toBe(false);
  });

  it('空文字の属性値はそのまま空文字として読み取る（属性なしとは区別する）', () => {
    const el = document.createElement('div');
    el.setAttribute('is-disabled', '');

    const result = readAttributesAsDataset(el, ['is-disabled']);

    expect(result).toEqual({ isDisabled: '' });
  });

  it('対象属性名リストが空なら空オブジェクトを返す', () => {
    const el = document.createElement('div');
    el.setAttribute('target', '.js-target');

    const result = readAttributesAsDataset(el, []);

    expect(result).toEqual({});
  });
});

describe('readForwardedHostAttributes', () => {
  it('root-class 属性は React の className キーに変換して読み取る', () => {
    const el = document.createElement('div');
    el.setAttribute('root-class', 'foo bar');

    const result = readForwardedHostAttributes(el, ['root-class']);

    expect(result).toEqual({ className: 'foo bar' });
  });

  it('root-class 以外の属性名はそのままのキーで読み取る（aria-* 等はそのまま React props として使える）', () => {
    const el = document.createElement('div');
    el.setAttribute('aria-label', 'ラベル');

    const result = readForwardedHostAttributes(el, ['aria-label']);

    expect(result).toEqual({ 'aria-label': 'ラベル' });
  });

  it('存在しない属性はキー自体を省略する', () => {
    const el = document.createElement('div');
    el.setAttribute('root-class', 'foo');

    const result = readForwardedHostAttributes(el, ['root-class', 'title']);

    expect(result).toEqual({ className: 'foo' });
    expect('title' in result).toBe(false);
  });

  it('複数の属性名を同時に読み取れる', () => {
    const el = document.createElement('div');
    el.setAttribute('root-class', 'foo');
    el.setAttribute('title', 'ツールチップ');

    const result = readForwardedHostAttributes(el, ['root-class', 'title']);

    expect(result).toEqual({ className: 'foo', title: 'ツールチップ' });
  });

  it('対象属性名リストが空なら空オブジェクトを返す', () => {
    const el = document.createElement('div');
    el.setAttribute('root-class', 'foo');

    const result = readForwardedHostAttributes(el, []);

    expect(result).toEqual({});
  });

  // グループユニットの外に出す操作等でこの要素が物理的に DOM 移動されると、Custom Elements の
  // 仕様により disconnectedCallback → connectedCallback が再発火する。root-class は host からは
  // 一切取り除かないため、何度 connectedCallback が呼ばれても同じ値を読み取れる（class を
  // 転送・削除していた旧実装では、2 回目以降の再発火で転送するクラスが失われ、例えば
  // block-editor の枠が消えるなどの見た目の不具合が起きていた）。
  it('connectedCallback が再発火しても root-class は消えないため同じ値を読み取れる', () => {
    const el = document.createElement('div');
    el.setAttribute('root-class', 'foo bar');

    const first = readForwardedHostAttributes(el, ['root-class']);
    const second = readForwardedHostAttributes(el, ['root-class']);

    expect(first).toEqual({ className: 'foo bar' });
    expect(second).toEqual({ className: 'foo bar' });
  });
});
