<commit_before>import { expect } from "chai";
import { runPCFile, loadModuleDependencyGraph, ComponentModule } from "..";
import { FakeAttribute, FakeDocument, FakeDocumentFragment, FakeElement, FakeTextNode, generateRandomStyleSheet } from "./utils";
import { renderDOM2, SlimParentNode, diffNode, patchNode2, patchDOM2, DOMNodeMap, setVMObjectIds, prepDiff, NativeObjectMap } from "slim-dom";

describe(__filename + "#", () => {
  it(`can render a component with a template`, async () => {
    const document = new FakeDocument();
    const body = document.createElement("body");
    const slimDoc = await runPCComponent({
      "entry.pc": `
        <component id="test">
          <template>
            <span>hello</span>
          </template>
          <preview name="main">
            <test />
          </preview>
        </component>
      `
    });
    renderDOM2(slimDoc, body as any);
    expect(body.toString()).to.eql(`<body><test class="__test_scope_host"><span class="__test_scope">hello</span></test></body>`);
  });


  it(`can render a component that has a slot and no child nodes`, async () => {
    const document = new FakeDocument();
    const body = document.createElement("body");
    const slimDoc = await runPCComponent({
      "entry.pc": `
        <component id="test">
          <template>
            <span><slot></slot></span>
          </template>
          <preview name="main">
            <test /><slot />
          </preview>
        </component>
      `
    });
    renderDOM2(slimDoc, body as any);
    expect(body.toString()).to.eql(`<body><test class="__test_scope_host"><span class="__test_scope"></span></test></body>`);
  });

  it(`can render a component with default slot children`, async () => {
    const document = new FakeDocument();
    const body = document.createElement("body");
    const slimDoc = await runPCComponent({
      "entry.pc": `
        <component id="test">
          <template>
            <span><slot></slot></span>
          </template>
          <preview name="main">
            <test>a <b /> c</test>
          </preview>
        </component>
      `
    });
    renderDOM2(slimDoc, body as any);
    expect(body.toString()).to.eql(`<body><test class="__test_scope_host"><span class="__test_scope">a <b></b> c</span></test></body>`);
  });

  it(`can render a component with named slots`, async () => {
    const document = new FakeDocument();
    const body = document.createElement("body");
    const slimDoc = await runPCComponent({
      "entry.pc": `
        <component id="test">
          <template>
            <span><slot></slot><slot name="a"></slot><slot name="b"></slot></span>
          </template>
          <preview name="main">
            <test>a <span slot="a">b</span><span slot="b">c</span><span slot="b">d</span>e</test>
          </preview>
        </component>
      `
    });
    renderDOM2(slimDoc, body as any);
    expect(body.toString()).to.eql(`<body><test class="__test_scope_host"><span class="__test_scope">a e<span slot="a">b</span><span slot="b">c</span><span slot="b">d</span></span></test></body>`);
  });

  describe("diff/patch", () => {
    [
      [
        // slot testing
        // add slotted child
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                <a /><b />
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                <a /><b /><c />
              </test>
            </preview>
          </component>
        `
      ],

      [
        `
          <component id="test">
            <template>
              <slot name="test"></slot>
            </template>
            <preview name="main">
              <test>
                <a slot="test"></a>
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot name="test"></slot>
            </template>
            <preview name="main">
              <test>
                <a slot="test"></a>
                <a slot="test"></a>
              </test>
            </preview>
          </component>
        `
      ],

      [
        `
          <component id="test">
            <template>
              <slot name="test"></slot>
            </template>
            <preview name="main">
              <test>
                <b slot="test"></b>
                <c slot="test2"></c>
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot name="test2"></slot>
            </template>
            <preview name="main">
              <test>
                <b slot="test"></b>
                <c slot="test2"></c>
              </test>
            </preview>
          </component>
        `
      ],

      [
        `
          <component id="test">
            <template>
              <div>
                <slot></slot>
              </div>
            </template>
            <preview name="main">
              <test>a</test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <span>
                <slot></slot>
              </span>
            </template>
            <preview name="main">
              <test>a</test>
            </preview>
          </component>
        `
      ],
      
      [
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                a
                <span slot="test2">b</span>
                c
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot name="slot2"></slot>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                a
                <span slot="test2">b</span>
                c
              </test>
            </preview>
          </component>
        `
      ],

      // add named slotted child
      [
        `
          <component id="test">
            <template>
              <a />
            </template>
            <preview name="main">
              <test />
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <b />
            </template>
            <preview name="main">
              <test />
            </preview>
          </component>
        `
      ],
      [
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                a b
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                b c
              </test>
            </preview>
          </component>
        `
      ]
    ].forEach((variants) => {
      it(`can diff & patch ${variants.join("->")}`, async () => {
        await diffPatchVariants(variants);
      });
    });

    describe("CSS", () => {
      [
        [`.a {}`, `.b {}`],
        [`.a {} .b {}`, `.b {} .a {}`],
        [`.a {} .b {}`, `.b {}`],
        [`.a {b: c; d: e;}`, `.b {d:e;b:c;}`],

        // busted fuzzy tests
        [`@keyframes a {}`, `@keyframes b {}`],
        [`@keyframes a { 0% { color: red; }}`, `@media b { .c { color: blue; }}`],
        [`.k { e: a;}`, `i { f: kb; e: k;} .i { a: e;}`],
        [`.i { h: ag;}`, `@media e { .f { h: ea;}}`, `.g { c: el;} @media k { .k { l: h; d: gk;}}`],
        [`.i { g: d; a: fk; g: ca;}`, `.f { g: d;}`],
        [`.d { a: h; i: le; h: j;}`, `.a { g: b; c: k; g: c;}  @keyframes j { 100% { a: kl;}  4% { g: c;}}`],
        [`.l { i: kj; g: dg;}`, `.b { k: c; g: d; i: e;}`]
      ].forEach((variants: any) => {
        it(`can diff & patch ${variants.join(" -> ")}`, async () => {
          await diffPatchVariants(variants.map(variant => {
            return `
            <component id="test">
              <style>
                ${variant}
              </style>
              <template>
                <slot></slot>
              </template>
              <preview name="main">
                <test />
              </preview>
            </component>
            `;
          }));
        });
      });
      describe(`fuzzy tests`, () => {

        const tests = Array.from({ length: 300 * 10 }).map(() => {
          return Array.from({ length: 4 }).map(() => generateRandomStyleSheet(10, 10))
        });

        tests.forEach((variants) => {
          it(`can diff & patch ${variants.join(" -> ")}`, async () => {
            await diffPatchVariants(variants.map(variant => {
              return `
              <component id="test">
                <style>
                  ${variant}
                </style>
                <template>
                  <slot></slot><commit_msg>get fuzzy tests to stable state<commit_after>import { expect } from "chai";
import { runPCFile, loadModuleDependencyGraph, ComponentModule } from "..";
import { FakeAttribute, FakeDocument, FakeDocumentFragment, FakeElement, FakeTextNode, generateRandomStyleSheet } from "./utils";
import { renderDOM2, SlimParentNode, diffNode, patchNode2, patchDOM2, DOMNodeMap, setVMObjectIds, prepDiff, NativeObjectMap } from "slim-dom";

describe(__filename + "#", () => {
  it(`can render a component with a template`, async () => {
    const document = new FakeDocument();
    const body = document.createElement("body");
    const slimDoc = await runPCComponent({
      "entry.pc": `
        <component id="test">
          <template>
            <span>hello</span>
          </template>
          <preview name="main">
            <test />
          </preview>
        </component>
      `
    });
    renderDOM2(slimDoc, body as any);
    expect(body.toString()).to.eql(`<body><test class="__test_scope_host"><span class="__test_scope">hello</span></test></body>`);
  });


  it(`can render a component that has a slot and no child nodes`, async () => {
    const document = new FakeDocument();
    const body = document.createElement("body");
    const slimDoc = await runPCComponent({
      "entry.pc": `
        <component id="test">
          <template>
            <span><slot></slot></span>
          </template>
          <preview name="main">
            <test /><slot />
          </preview>
        </component>
      `
    });
    renderDOM2(slimDoc, body as any);
    expect(body.toString()).to.eql(`<body><test class="__test_scope_host"><span class="__test_scope"></span></test></body>`);
  });

  it(`can render a component with default slot children`, async () => {
    const document = new FakeDocument();
    const body = document.createElement("body");
    const slimDoc = await runPCComponent({
      "entry.pc": `
        <component id="test">
          <template>
            <span><slot></slot></span>
          </template>
          <preview name="main">
            <test>a <b /> c</test>
          </preview>
        </component>
      `
    });
    renderDOM2(slimDoc, body as any);
    expect(body.toString()).to.eql(`<body><test class="__test_scope_host"><span class="__test_scope">a <b></b> c</span></test></body>`);
  });

  it(`can render a component with named slots`, async () => {
    const document = new FakeDocument();
    const body = document.createElement("body");
    const slimDoc = await runPCComponent({
      "entry.pc": `
        <component id="test">
          <template>
            <span><slot></slot><slot name="a"></slot><slot name="b"></slot></span>
          </template>
          <preview name="main">
            <test>a <span slot="a">b</span><span slot="b">c</span><span slot="b">d</span>e</test>
          </preview>
        </component>
      `
    });
    renderDOM2(slimDoc, body as any);
    expect(body.toString()).to.eql(`<body><test class="__test_scope_host"><span class="__test_scope">a e<span slot="a">b</span><span slot="b">c</span><span slot="b">d</span></span></test></body>`);
  });

  describe("diff/patch", () => {
    [
      [
        // slot testing
        // add slotted child
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                <a /><b />
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                <a /><b /><c />
              </test>
            </preview>
          </component>
        `
      ],

      [
        `
          <component id="test">
            <template>
              <slot name="test"></slot>
            </template>
            <preview name="main">
              <test>
                <a slot="test"></a>
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot name="test"></slot>
            </template>
            <preview name="main">
              <test>
                <a slot="test"></a>
                <a slot="test"></a>
              </test>
            </preview>
          </component>
        `
      ],

      [
        `
          <component id="test">
            <template>
              <slot name="test"></slot>
            </template>
            <preview name="main">
              <test>
                <b slot="test"></b>
                <c slot="test2"></c>
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot name="test2"></slot>
            </template>
            <preview name="main">
              <test>
                <b slot="test"></b>
                <c slot="test2"></c>
              </test>
            </preview>
          </component>
        `
      ],

      [
        `
          <component id="test">
            <template>
              <div>
                <slot></slot>
              </div>
            </template>
            <preview name="main">
              <test>a</test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <span>
                <slot></slot>
              </span>
            </template>
            <preview name="main">
              <test>a</test>
            </preview>
          </component>
        `
      ],
      
      [
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                a
                <span slot="test2">b</span>
                c
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot name="slot2"></slot>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                a
                <span slot="test2">b</span>
                c
              </test>
            </preview>
          </component>
        `
      ],

      // add named slotted child
      [
        `
          <component id="test">
            <template>
              <a />
            </template>
            <preview name="main">
              <test />
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <b />
            </template>
            <preview name="main">
              <test />
            </preview>
          </component>
        `
      ],
      [
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                a b
              </test>
            </preview>
          </component>
        `,
        `
          <component id="test">
            <template>
              <slot></slot>
            </template>
            <preview name="main">
              <test>
                b c
              </test>
            </preview>
          </component>
        `
      ]
    ].forEach((variants) => {
      it(`can diff & patch ${variants.join("->")}`, async () => {
        await diffPatchVariants(variants);
      });
    });

    describe("CSS", () => {
      [
        [`.a {}`, `.b {}`],
        [`.a {} .b {}`, `.b {} .a {}`],
        [`.a {} .b {}`, `.b {}`],
        [`.a {b: c; d: e;}`, `.b {d:e;b:c;}`],

        // busted fuzzy tests
        [`@keyframes a {}`, `@keyframes b {}`],
        [`@keyframes a { 0% { color: red; }}`, `@media b { .c { color: blue; }}`],
        [`.k { e: a;}`, `i { f: kb; e: k;} .i { a: e;}`],
        [`.i { h: ag;}`, `@media e { .f { h: ea;}}`, `.g { c: el;} @media k { .k { l: h; d: gk;}}`],
        [`.i { g: d; a: fk; g: ca;}`, `.f { g: d;}`],
        [`.d { a: h; i: le; h: j;}`, `.a { g: b; c: k; g: c;}  @keyframes j { 100% { a: kl;}  4% { g: c;}}`],
        [`.l { i: kj; g: dg;}`, `.b { k: c; g: d; i: e;}`]
      ].forEach((variants: any) => {
        it(`can diff & patch ${variants.join(" -> ")}`, async () => {
          await diffPatchVariants(variants.map(variant => {
            return `
            <component id="test">
              <style>
                ${variant}
              </style>
              <template>
                <slot></slot>
              </template>
              <preview name="main">
                <test />
              </preview>
            </component>
            `;
          }));
        });
      });
      describe(`fuzzy tests`, () => {

        const tests = Array.from({ length: 300 }).map(() => {
          return Array.from({ length: 4 }).map(() => generateRandomStyleSheet(5, 5))
        });

        tests.forEach((variants) => {
          it(`can diff & patch ${variants.join(" -> ")}`, async () => {
            await diffPatchVariants(variants.map(variant => {
              return `
              <component id="test">
                <style>
                  ${variant}
                </style>
                <template>
                  <slot></slot>
{'fraction_non_alphanumeric': 0.17423564700310476, 'fraction_numerical': 0.002736410040519918, 'mean_word_length': 1.2694053021256269, 'pattern_counts': {'":': 8, '<': 543, '<?xml version=': 0, '>': 585, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1880207', 'n_tokens_mistral': 5455, 'n_tokens_neox': 5328, 'n_words': 1145}