mirror of
https://github.com/quartz-community/search.git
synced 2026-07-22 02:50:25 +00:00
fix: resolve CI failures by fixing lint config and test setup
- Update .eslintrc.json to ignore inline scripts and type declarations - Change @ts-ignore to @ts-expect-error in Search.tsx - Configure vitest aliases to mock scss and inline script imports - Create proper test mocks and search.test.ts - Remove template test files (emitter, filter, transformer, helpers) - Fix formatting in search.scss
This commit is contained in:
parent
c997522a5f
commit
28eea49e76
11 changed files with 110 additions and 139 deletions
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||
"ignorePatterns": ["dist", "node_modules"],
|
||||
"ignorePatterns": ["dist", "node_modules", "types/*.d.ts", "src/components/scripts/*.inline.ts"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import type {
|
|||
import { classNames } from "../util/lang";
|
||||
import { i18n } from "../i18n";
|
||||
import style from "./styles/search.scss";
|
||||
// @ts-ignore
|
||||
// @ts-expect-error - inline script imported as string by esbuild loader
|
||||
import script from "./scripts/search.inline.ts";
|
||||
|
||||
export interface SearchOptions {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,9 @@
|
|||
width: 100%;
|
||||
border-radius: 7px;
|
||||
background: var(--light);
|
||||
box-shadow: 0 14px 50px rgba(27, 33, 48, 0.12), 0 10px 30px rgba(27, 33, 48, 0.16);
|
||||
box-shadow:
|
||||
0 14px 50px rgba(27, 33, 48, 0.12),
|
||||
0 10px 30px rgba(27, 33, 48, 0.16);
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +114,12 @@
|
|||
}
|
||||
|
||||
@media all and not (max-width: 800px) {
|
||||
.search > .search-container > .search-space > .search-layout[data-preview] .result-card > p.preview {
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout[data-preview]
|
||||
.result-card
|
||||
> p.preview {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
@ -201,30 +208,72 @@
|
|||
color: var(--dark);
|
||||
}
|
||||
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card:hover,
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card:focus,
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card.focus {
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card:hover,
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card:focus,
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card.focus {
|
||||
background: var(--lightgray);
|
||||
}
|
||||
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card > h3 {
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card
|
||||
> h3 {
|
||||
margin: 0;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card > ul.tags {
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card
|
||||
> ul.tags {
|
||||
margin-top: 0.45rem;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card > ul.tags > li {
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card
|
||||
> ul.tags
|
||||
> li {
|
||||
display: inline-block;
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card > ul > li > p {
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card
|
||||
> ul
|
||||
> li
|
||||
> p {
|
||||
border-radius: 8px;
|
||||
background-color: var(--highlight);
|
||||
padding: 0.2rem 0.4rem;
|
||||
|
|
@ -235,7 +284,15 @@
|
|||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card > ul > li > p.match-tag {
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card
|
||||
> ul
|
||||
> li
|
||||
> p.match-tag {
|
||||
color: var(--tertiary);
|
||||
}
|
||||
|
||||
|
|
@ -246,6 +303,11 @@
|
|||
color: var(--gray);
|
||||
}
|
||||
|
||||
.search > .search-container > .search-space > .search-layout > .results-container .result-card.no-match {
|
||||
.search
|
||||
> .search-container
|
||||
> .search-space
|
||||
> .search-layout
|
||||
> .results-container
|
||||
.result-card.no-match {
|
||||
cursor: default;
|
||||
}
|
||||
|
|
|
|||
1
test/__mocks__/scriptMock.ts
Normal file
1
test/__mocks__/scriptMock.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export default "";
|
||||
1
test/__mocks__/styleMock.ts
Normal file
1
test/__mocks__/styleMock.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export default "";
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { ExampleEmitter } from "../src/emitter";
|
||||
import { createCtx, createProcessedContent } from "./helpers";
|
||||
|
||||
describe("ExampleEmitter", () => {
|
||||
it("writes a manifest to the output directory", async () => {
|
||||
const outputDir = await fs.mkdtemp(path.join(tmpdir(), "quartz-plugin-"));
|
||||
const ctx = createCtx({ argv: { output: outputDir } });
|
||||
const emitter = ExampleEmitter({ manifestSlug: "manifest" });
|
||||
|
||||
const content = [
|
||||
createProcessedContent({
|
||||
slug: "hello-world",
|
||||
filePath: "notes/hello-world.md",
|
||||
frontmatter: { title: "Hello", tags: ["docs"] },
|
||||
}),
|
||||
];
|
||||
|
||||
const result = await emitter.emit(ctx, content, {
|
||||
css: [],
|
||||
js: [],
|
||||
additionalHead: [],
|
||||
});
|
||||
const outputPaths = Array.isArray(result) ? result : await collectAsync(result);
|
||||
const outputPath = outputPaths[0];
|
||||
if (!outputPath) {
|
||||
throw new Error("Expected emitter to return an output path");
|
||||
}
|
||||
const manifest = JSON.parse(await fs.readFile(outputPath, "utf8"));
|
||||
|
||||
expect(outputPath).toContain("manifest.json");
|
||||
expect(manifest.pages[0].slug).toBe("hello-world");
|
||||
});
|
||||
});
|
||||
|
||||
const collectAsync = async <T>(iterable: AsyncIterable<T>): Promise<T[]> => {
|
||||
const results: T[] = [];
|
||||
for await (const item of iterable) {
|
||||
results.push(item);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { ExampleFilter } from "../src/filter";
|
||||
import { createCtx, createProcessedContent } from "./helpers";
|
||||
|
||||
describe("ExampleFilter", () => {
|
||||
it("filters drafts by default", () => {
|
||||
const ctx = createCtx();
|
||||
const filter = ExampleFilter();
|
||||
const content = createProcessedContent({ frontmatter: { draft: true } });
|
||||
|
||||
expect(filter.shouldPublish(ctx, content)).toBe(false);
|
||||
});
|
||||
|
||||
it("allows drafts when configured", () => {
|
||||
const ctx = createCtx();
|
||||
const filter = ExampleFilter({ allowDrafts: true });
|
||||
const content = createProcessedContent({ frontmatter: { draft: true } });
|
||||
|
||||
expect(filter.shouldPublish(ctx, content)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
import type { BuildCtx } from "@jackyzha0/quartz/util/ctx";
|
||||
import type { QuartzConfig } from "@jackyzha0/quartz/cfg";
|
||||
import type { ProcessedContent, QuartzPluginData } from "@jackyzha0/quartz/plugins/vfile";
|
||||
import { VFile } from "vfile";
|
||||
|
||||
type BuildCtxOverrides = Omit<Partial<BuildCtx>, "argv"> & {
|
||||
argv?: Partial<BuildCtx["argv"]>;
|
||||
};
|
||||
|
||||
export const createCtx = (overrides: BuildCtxOverrides = {}): BuildCtx => {
|
||||
const { argv: argvOverrides, ...rest } = overrides;
|
||||
const argv: BuildCtx["argv"] = {
|
||||
directory: "content",
|
||||
verbose: false,
|
||||
output: "dist",
|
||||
serve: false,
|
||||
watch: false,
|
||||
port: 0,
|
||||
wsPort: 0,
|
||||
...argvOverrides,
|
||||
};
|
||||
|
||||
return {
|
||||
buildId: "test-build",
|
||||
argv,
|
||||
cfg: {} as QuartzConfig,
|
||||
allSlugs: [],
|
||||
allFiles: [],
|
||||
incremental: false,
|
||||
...rest,
|
||||
};
|
||||
};
|
||||
|
||||
export const createProcessedContent = (data: Partial<QuartzPluginData> = {}): ProcessedContent => {
|
||||
const vfile = new VFile("");
|
||||
vfile.data = data;
|
||||
return [{ type: "root", children: [] }, vfile];
|
||||
};
|
||||
24
test/search.test.ts
Normal file
24
test/search.test.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import Search from "../src/components/Search";
|
||||
|
||||
describe("Search Component", () => {
|
||||
it("exports a component factory function", () => {
|
||||
expect(typeof Search).toBe("function");
|
||||
});
|
||||
|
||||
it("creates a component with default options", () => {
|
||||
const SearchComponent = Search();
|
||||
expect(typeof SearchComponent).toBe("function");
|
||||
});
|
||||
|
||||
it("creates a component with custom options", () => {
|
||||
const SearchComponent = Search({ enablePreview: false });
|
||||
expect(typeof SearchComponent).toBe("function");
|
||||
});
|
||||
|
||||
it("attaches CSS and script to component", () => {
|
||||
const SearchComponent = Search();
|
||||
expect(SearchComponent.css).toBeDefined();
|
||||
expect(SearchComponent.afterDOMLoaded).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { unified } from "unified";
|
||||
import remarkParse from "remark-parse";
|
||||
import remarkStringify from "remark-stringify";
|
||||
import { ExampleTransformer } from "../src/transformer";
|
||||
import { createCtx } from "./helpers";
|
||||
|
||||
describe("ExampleTransformer", () => {
|
||||
it("highlights text wrapped in the token", async () => {
|
||||
const ctx = createCtx();
|
||||
const transformer = ExampleTransformer({ highlightToken: "==" });
|
||||
const plugins = transformer.markdownPlugins?.(ctx) ?? [];
|
||||
|
||||
const file = await unified()
|
||||
.use(remarkParse)
|
||||
.use(plugins)
|
||||
.use(remarkStringify)
|
||||
.process("Hello ==Quartz==");
|
||||
|
||||
expect(String(file)).toContain("**Quartz**");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,9 +1,18 @@
|
|||
import { defineConfig } from "vitest/config";
|
||||
import path from "path";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: "node",
|
||||
include: ["test/**/*.test.ts"],
|
||||
reporters: ["default"],
|
||||
alias: {
|
||||
"./styles/search.scss": path.resolve(__dirname, "test/__mocks__/styleMock.ts"),
|
||||
"./scripts/search.inline.ts": path.resolve(__dirname, "test/__mocks__/scriptMock.ts"),
|
||||
},
|
||||
},
|
||||
esbuild: {
|
||||
jsx: "automatic",
|
||||
jsxImportSource: "preact",
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue