# test.govlab/quality/core/stylelint/no-held-entrance-fill.stylelint.rule.test.ts

> 47 lines of code and 0 definitions.

Tree: Codebase Testing
Language: typescript
Canonical: https://banes-lab.com/anatomy/testing#file-testing-test-govlab-quality-core-stylelint-no-held-entrance-fill-stylelint-rule-test-ts
Source text: https://banes-lab.com/source/testing/test.govlab/quality/core/stylelint/no-held-entrance-fill.stylelint.rule.test.ts.txt

Listed in [test.govlab/quality/core/stylelint](https://banes-lab.com/api/source/testing/test.govlab/quality/core/stylelint.md), after [test.govlab/quality/core/stylelint/no-custom-property-redefinition.stylelint.rule.test.ts](https://banes-lab.com/source/testing/test.govlab/quality/core/stylelint/no-custom-property-redefinition.stylelint.rule.test.ts.md) and before [test.govlab/quality/core/stylelint/no-large-viewport-unit.stylelint.rule.test.ts](https://banes-lab.com/source/testing/test.govlab/quality/core/stylelint/no-large-viewport-unit.stylelint.rule.test.ts.md).

## Contained in

- [test.govlab/quality/core/stylelint](https://banes-lab.com/anatomy/testing/folder-testing-test-govlab-quality-core-stylelint.md)

## Source

```typescript
import { describe, expect, it } from "vitest";
import { mkdirSync, mkdtempSync } from "node:fs";
import { join } from "node:path";
import noHeldEntranceFill from "@govlab/quality/core/stylelint/no-held-entrance-fill.stylelint.rule.ts";
import stylelint from "stylelint";
import { tmpdir } from "node:os";
import { writeVerbatim } from "@govlab/canonical-write";

const RULE = "govlab/no-held-entrance-fill";
const FADE = "@keyframes fade { from { opacity: 0; } to { opacity: 1; } }";
const FADE_OUT = "@keyframes vanish { 0% { opacity: 1; } 100% { opacity: 0; } }";

const lint = async function lint(code: string): Promise<readonly string[]> {
    const result = await stylelint.lint({ code, config: { plugins: [noHeldEntranceFill], rules: { [RULE]: true } } });
    return result.results.flatMap((entry) => entry.warnings.map((warning) => warning.rule));
};

describe("govlab/no-held-entrance-fill", () => {
    it("reports a shorthand that holds an opaque end with both or forwards", async () => {
        expect(await lint(`${FADE} .card { animation: fade 1s ease both; }`)).toStrictEqual([RULE]);
        expect(await lint(`${FADE} .card { animation: fade 1s forwards; }`)).toStrictEqual([RULE]);
    });

    it("reports the held layer among several", async () => {
        expect(await lint(`${FADE} ${FADE_OUT} .card { animation: vanish 1s, fade 1s both; }`)).toStrictEqual([RULE]);
    });

    it("reports longhands that hold an opaque end", async () => {
        const code = `${FADE} .card { animation-name: fade; animation-fill-mode: both; }`;
        expect(await lint(code)).toStrictEqual([RULE]);
    });

    it("allows an entrance that fills backwards and rests on the element's own rule", async () => {
        expect(await lint(`${FADE} .card { animation: fade 1s backwards; opacity: 1; }`)).toStrictEqual([]);
    });

    it("allows holding an exit that ends transparent", async () => {
        expect(await lint(`${FADE_OUT} .card { animation: vanish 1s forwards; }`)).toStrictEqual([]);
    });

    it("reads keyframes declared in another stylesheet of the same member", async () => {
        const member = mkdtempSync(join(tmpdir(), "held-fill-"));
        mkdirSync(join(member, "effects"));
        writeVerbatim(join(member, "package.json"), "{}");
        writeVerbatim(join(member, "effects", "pop.effect.css"), FADE);
        const codeFilename = join(member, "dialog.style.css");
        const code = ".dialog { animation: fade 1s forwards; }";
        const result = await stylelint.lint({
            code,
            codeFilename,
            config: { plugins: [noHeldEntranceFill], rules: { [RULE]: true } },
        });
        expect(result.results.flatMap((entry) => entry.warnings.map((warning) => warning.rule))).toStrictEqual([RULE]);
    });
});
```
