Initial Commit
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
import { mkdtemp, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import { checkRoots } from "../../../../../scripts/lint/check-no-hardcoded-strings.js";
|
||||
|
||||
async function makeTempFile(name: string, body: string): Promise<string> {
|
||||
const dir = await mkdtemp(join(tmpdir(), "no-hardcoded-strings-"));
|
||||
const file = join(dir, name);
|
||||
await writeFile(file, body, "utf8");
|
||||
return dir;
|
||||
}
|
||||
|
||||
describe("check-no-hardcoded-strings", () => {
|
||||
it(
|
||||
"passes a t-wrapped JSX text node",
|
||||
{ timeout: 10000 },
|
||||
async () => {
|
||||
const root = await makeTempFile(
|
||||
"ok.tsx",
|
||||
`import { useTranslation } from '@suaveplan/react-i18n';
|
||||
export function X() {
|
||||
const { t } = useTranslation();
|
||||
return <button type="button">{t('react-ui.themeToggle.label')}</button>;
|
||||
}
|
||||
`
|
||||
);
|
||||
const diagnostics = await checkRoots([{ root }]);
|
||||
expect(diagnostics).toEqual([]);
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
"fails a bare JSX text node",
|
||||
{ timeout: 10000 },
|
||||
async () => {
|
||||
const root = await makeTempFile(
|
||||
"bad.tsx",
|
||||
`export function X() {
|
||||
return <button type="button">Close</button>;
|
||||
}
|
||||
`
|
||||
);
|
||||
const diagnostics = await checkRoots([{ root }]);
|
||||
expect(diagnostics.length).toBeGreaterThanOrEqual(1);
|
||||
expect(diagnostics[0]?.rule).toBe("jsx-text");
|
||||
expect(diagnostics[0]?.snippet).toBe("Close");
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
"fails a string literal aria-label",
|
||||
{ timeout: 10000 },
|
||||
async () => {
|
||||
const root = await makeTempFile(
|
||||
"aria.tsx",
|
||||
`export function X() {
|
||||
return <button type="button" aria-label="Close" />;
|
||||
}
|
||||
`
|
||||
);
|
||||
const diagnostics = await checkRoots([{ root }]);
|
||||
expect(diagnostics.length).toBeGreaterThanOrEqual(1);
|
||||
expect(diagnostics[0]?.rule).toBe("jsx-attr-aria-label");
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
"fails an object-literal label string",
|
||||
{ timeout: 10000 },
|
||||
async () => {
|
||||
const root = await makeTempFile(
|
||||
"obj.ts",
|
||||
`export const fields = { email: { label: 'Email' } };
|
||||
`
|
||||
);
|
||||
const diagnostics = await checkRoots([{ root }]);
|
||||
expect(diagnostics.length).toBeGreaterThanOrEqual(1);
|
||||
expect(diagnostics[0]?.rule).toBe("object-label");
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
"fails a JSX expression string-literal child",
|
||||
{ timeout: 10000 },
|
||||
async () => {
|
||||
const root = await makeTempFile(
|
||||
"literal.tsx",
|
||||
`export function X() {
|
||||
return <span>{'hardcoded'}</span>;
|
||||
}
|
||||
`
|
||||
);
|
||||
const diagnostics = await checkRoots([{ root }]);
|
||||
expect(diagnostics.length).toBeGreaterThanOrEqual(1);
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
"fails a string-literal placeholder attribute",
|
||||
{ timeout: 10000 },
|
||||
async () => {
|
||||
const root = await makeTempFile(
|
||||
"placeholder.tsx",
|
||||
`export function X() {
|
||||
return <input type="text" placeholder="Email address" />;
|
||||
}
|
||||
`
|
||||
);
|
||||
const diagnostics = await checkRoots([{ root }]);
|
||||
expect(diagnostics.length).toBeGreaterThanOrEqual(1);
|
||||
expect(diagnostics[0]?.rule).toBe("jsx-attr-placeholder");
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
"skips test/spec/stories files via the skip suffix list",
|
||||
{ timeout: 10000 },
|
||||
async () => {
|
||||
const root = await makeTempFile(
|
||||
"thing.test.tsx",
|
||||
`export function X() {
|
||||
return <button type="button">hardcoded but exempt</button>;
|
||||
}
|
||||
`
|
||||
);
|
||||
const diagnostics = await checkRoots([{ root }]);
|
||||
expect(diagnostics).toEqual([]);
|
||||
}
|
||||
);
|
||||
|
||||
it(
|
||||
"skips spike directories",
|
||||
{ timeout: 10000 },
|
||||
async () => {
|
||||
const dir = await mkdtemp(join(tmpdir(), "spike-skip-"));
|
||||
const spikeDir = join(dir, "spike");
|
||||
const fs = await import("node:fs/promises");
|
||||
await fs.mkdir(spikeDir, { recursive: true });
|
||||
await fs.writeFile(
|
||||
join(spikeDir, "x.tsx"),
|
||||
`export function X() {
|
||||
return <button type="button">spike literal</button>;
|
||||
}
|
||||
`
|
||||
);
|
||||
const diagnostics = await checkRoots([{ root: dir }]);
|
||||
expect(diagnostics).toEqual([]);
|
||||
}
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user