Skip to content

Commit 3b72b10

Browse files
committed
Add tests
1 parent eebef5c commit 3b72b10

File tree

13 files changed

+1083
-5
lines changed

13 files changed

+1083
-5
lines changed

.github/workflows/tests.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Tests
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
paths:
7+
- 'packages/starlight-giscus/**'
8+
- '.github/workflows/tests.yml'
9+
10+
jobs:
11+
test:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@v6
16+
17+
- uses: pnpm/action-setup@v4
18+
with:
19+
run_install: false
20+
21+
- uses: actions/setup-node@v6
22+
with:
23+
node-version: lts/*
24+
cache: pnpm
25+
26+
- name: Install dependencies
27+
run: pnpm install --frozen-lockfile
28+
29+
- name: Run type check
30+
run: pnpm --filter ./packages/starlight-giscus typecheck
31+
32+
- name: Run tests
33+
run: pnpm --filter ./packages/starlight-giscus test
34+
35+
- name: Run tests with coverage
36+
run: pnpm --filter ./packages/starlight-giscus test:coverage

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ pnpm-debug.log*
2121
.DS_Store
2222

2323
.vscode/
24-
.idea/
24+
.idea/
25+
26+
packages/starlight-giscus/coverage
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
tsconfig.json
2+
tsconfig.build.json
3+
vitest.config.ts
4+
tests
5+
coverage
6+
*.test.ts

packages/starlight-giscus/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ function validateAndNormalizeConfig(
8383
};
8484
}
8585

86+
export { validateAndNormalizeConfig };
87+
8688
export default function starlightGiscus(
8789
options: StarlightGiscusUserConfig
8890
): StarlightPlugin {

packages/starlight-giscus/package.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "starlight-giscus",
3-
"version": "0.9.0",
3+
"version": "0.9.1",
44
"license": "MIT",
55
"description": "A Starlight plugin for adding Giscus comments to your documentation.",
66
"keywords": [
@@ -14,11 +14,26 @@
1414
],
1515
"author": "Bugo",
1616
"type": "module",
17+
"types": "./index.ts",
18+
"scripts": {
19+
"test": "vitest run",
20+
"test:watch": "vitest",
21+
"test:ui": "vitest --ui",
22+
"test:coverage": "vitest run --coverage",
23+
"typecheck": "tsc-files --noEmit index.ts libs/starlight.ts libs/vite.ts tests/*.test.ts"
24+
},
1725
"exports": {
1826
".": "./index.ts",
1927
"./components/Comments.astro": "./components/Comments.astro",
2028
"./overrides/Pagination.astro": "./overrides/Pagination.astro",
2129
"./package.json": "./package.json"
30+
},
31+
"devDependencies": {
32+
"@vitest/coverage-v8": "^4.0.18",
33+
"@vitest/ui": "^4.0.18",
34+
"tsc-files": "^1.1.4",
35+
"vite": "^7.3.1",
36+
"vitest": "^4.0.18"
2237
},
2338
"peerDependencies": {
2439
"@astrojs/starlight": ">=0.37.0"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Tests
2+
3+
This directory contains unit tests for the starlight-giscus plugin.
4+
5+
## Running Tests
6+
7+
```bash
8+
# Run tests once
9+
pnpm test
10+
11+
# Run tests in watch mode
12+
pnpm run test:watch
13+
14+
# Run tests with UI
15+
pnpm run test:ui
16+
17+
# Run tests with coverage
18+
pnpm run test:coverage
19+
20+
# Type check
21+
pnpm run typecheck
22+
```
23+
24+
## Test Coverage
25+
26+
Current coverage: **100%**
27+
28+
- `validate-config.test.ts` (17 tests) - Configuration validation and normalization
29+
- `override-component.test.ts` (6 tests) - Starlight component override logic
30+
- `vite-plugin.test.ts` (7 tests) - Vite virtual module plugin
31+
- `plugin.test.ts` (7 tests) - Main plugin integration and hooks
32+
33+
**Total: 37 tests**
34+
35+
## Test Structure
36+
37+
Each test file follows the pattern:
38+
- Unit tests for individual functions
39+
- Edge case testing
40+
- Error handling validation
41+
- Integration testing where applicable
42+
43+
## Coverage Details
44+
45+
All source files have 100% coverage:
46+
- `index.ts` - 100% (statements, branches, functions, lines)
47+
- `libs/starlight.ts` - 100%
48+
- `libs/vite.ts` - 100%
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
import { overrideStarlightComponent } from '../libs/starlight';
3+
import type { AstroIntegrationLogger } from 'astro';
4+
5+
describe('overrideStarlightComponent', () => {
6+
const createMockLogger = (): AstroIntegrationLogger => ({
7+
warn: vi.fn(),
8+
info: vi.fn(),
9+
error: vi.fn(),
10+
debug: vi.fn(),
11+
label: 'test',
12+
fork: vi.fn(),
13+
} as any);
14+
15+
it('should return override path when component is not already overridden', () => {
16+
const logger = createMockLogger();
17+
const result = overrideStarlightComponent(undefined, logger, 'Pagination', 'Pagination');
18+
19+
expect(result).toEqual({
20+
Pagination: 'starlight-giscus/overrides/Pagination.astro',
21+
});
22+
expect(logger.warn).not.toHaveBeenCalled();
23+
});
24+
25+
it('should return override path when components object is empty', () => {
26+
const logger = createMockLogger();
27+
const result = overrideStarlightComponent({}, logger, 'Pagination', 'Pagination');
28+
29+
expect(result).toEqual({
30+
Pagination: 'starlight-giscus/overrides/Pagination.astro',
31+
});
32+
expect(logger.warn).not.toHaveBeenCalled();
33+
});
34+
35+
it('should return empty object when component is already overridden', () => {
36+
const logger = createMockLogger();
37+
const components = { Pagination: 'custom/Pagination.astro' };
38+
const result = overrideStarlightComponent(components, logger, 'Pagination', 'Pagination');
39+
40+
expect(result).toEqual({});
41+
});
42+
43+
it('should log warning when component is already overridden', () => {
44+
const logger = createMockLogger();
45+
const components = { Pagination: 'custom/Pagination.astro' };
46+
overrideStarlightComponent(components, logger, 'Pagination', 'Pagination');
47+
48+
expect(logger.warn).toHaveBeenCalledTimes(2);
49+
expect(logger.warn).toHaveBeenCalledWith(
50+
'It looks like you already have a `Pagination` component override in your Starlight configuration.'
51+
);
52+
expect(logger.warn).toHaveBeenCalledWith(
53+
'To use `starlight-giscus`, either remove your override or update it to render the content from `starlight-giscus/components/Pagination.astro`.'
54+
);
55+
});
56+
57+
it('should handle different component names', () => {
58+
const logger = createMockLogger();
59+
const result = overrideStarlightComponent(undefined, logger, 'Footer', 'Footer');
60+
61+
expect(result).toEqual({
62+
Footer: 'starlight-giscus/overrides/Footer.astro',
63+
});
64+
});
65+
66+
it('should not override when other components are overridden', () => {
67+
const logger = createMockLogger();
68+
const components = { Footer: 'custom/Footer.astro' };
69+
const result = overrideStarlightComponent(components, logger, 'Pagination', 'Pagination');
70+
71+
expect(result).toEqual({
72+
Pagination: 'starlight-giscus/overrides/Pagination.astro',
73+
});
74+
expect(logger.warn).not.toHaveBeenCalled();
75+
});
76+
});
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
import starlightGiscus from '../index';
3+
import type { StarlightGiscusUserConfig } from '../index';
4+
5+
describe('starlightGiscus plugin', () => {
6+
const validConfig: StarlightGiscusUserConfig = {
7+
repo: 'user/repo',
8+
repoId: 'R_123',
9+
category: 'General',
10+
categoryId: 'DIC_123',
11+
};
12+
13+
it('should create a plugin with correct name', () => {
14+
const plugin = starlightGiscus(validConfig);
15+
expect(plugin.name).toBe('starlight-giscus');
16+
});
17+
18+
it('should have config:setup hook', () => {
19+
const plugin = starlightGiscus(validConfig);
20+
expect(plugin.hooks).toBeDefined();
21+
expect(plugin.hooks['config:setup']).toBeDefined();
22+
expect(typeof plugin.hooks['config:setup']).toBe('function');
23+
});
24+
25+
it('should throw error for invalid config', () => {
26+
const invalidConfig = { repo: 'user/repo' } as StarlightGiscusUserConfig;
27+
expect(() => starlightGiscus(invalidConfig)).toThrow();
28+
});
29+
30+
it('should call updateConfig in hook', () => {
31+
const plugin = starlightGiscus(validConfig);
32+
const updateConfig = vi.fn();
33+
const addIntegration = vi.fn();
34+
const logger = {
35+
warn: vi.fn(),
36+
info: vi.fn(),
37+
error: vi.fn(),
38+
debug: vi.fn(),
39+
label: 'test',
40+
fork: vi.fn(),
41+
} as any;
42+
43+
const configSetup = plugin.hooks['config:setup'];
44+
expect(configSetup).toBeDefined();
45+
46+
configSetup!({
47+
logger,
48+
config: { title: 'Test', components: {} } as any,
49+
updateConfig,
50+
addIntegration,
51+
command: 'dev',
52+
isRestart: false,
53+
} as any);
54+
55+
expect(updateConfig).toHaveBeenCalled();
56+
expect(addIntegration).toHaveBeenCalled();
57+
});
58+
59+
it('should add Pagination component override', () => {
60+
const plugin = starlightGiscus(validConfig);
61+
const updateConfig = vi.fn();
62+
const addIntegration = vi.fn();
63+
const logger = {
64+
warn: vi.fn(),
65+
info: vi.fn(),
66+
error: vi.fn(),
67+
debug: vi.fn(),
68+
label: 'test',
69+
fork: vi.fn(),
70+
} as any;
71+
72+
const configSetup = plugin.hooks['config:setup'];
73+
expect(configSetup).toBeDefined();
74+
75+
configSetup!({
76+
logger,
77+
config: { title: 'Test', components: {} } as any,
78+
updateConfig,
79+
addIntegration,
80+
command: 'dev',
81+
isRestart: false,
82+
} as any);
83+
84+
const updateCall = updateConfig.mock.calls[0][0];
85+
expect(updateCall.components).toBeDefined();
86+
expect(updateCall.components.Pagination).toBe(
87+
'starlight-giscus/overrides/Pagination.astro'
88+
);
89+
});
90+
91+
it('should add astro:config:setup integration', () => {
92+
const plugin = starlightGiscus(validConfig);
93+
const updateConfig = vi.fn();
94+
const addIntegration = vi.fn();
95+
const logger = {
96+
warn: vi.fn(),
97+
info: vi.fn(),
98+
error: vi.fn(),
99+
debug: vi.fn(),
100+
label: 'test',
101+
fork: vi.fn(),
102+
} as any;
103+
104+
const configSetup = plugin.hooks['config:setup'];
105+
expect(configSetup).toBeDefined();
106+
107+
configSetup!({
108+
logger,
109+
config: { title: 'Test', components: {} } as any,
110+
updateConfig,
111+
addIntegration,
112+
command: 'dev',
113+
isRestart: false,
114+
} as any);
115+
116+
expect(addIntegration).toHaveBeenCalledWith(
117+
expect.objectContaining({
118+
name: 'starlight-giscus-integration',
119+
hooks: expect.objectContaining({
120+
'astro:config:setup': expect.any(Function),
121+
}),
122+
})
123+
);
124+
});
125+
126+
it('should configure vite plugin in astro:config:setup hook', () => {
127+
const plugin = starlightGiscus(validConfig);
128+
const updateConfig = vi.fn();
129+
const addIntegration = vi.fn();
130+
const logger = {
131+
warn: vi.fn(),
132+
info: vi.fn(),
133+
error: vi.fn(),
134+
debug: vi.fn(),
135+
label: 'test',
136+
fork: vi.fn(),
137+
} as any;
138+
139+
const configSetup = plugin.hooks['config:setup'];
140+
configSetup!({
141+
logger,
142+
config: { title: 'Test', components: {} } as any,
143+
updateConfig,
144+
addIntegration,
145+
command: 'dev',
146+
isRestart: false,
147+
} as any);
148+
149+
// Get the integration that was added
150+
const integration = addIntegration.mock.calls[0][0];
151+
const astroConfigSetup = integration.hooks['astro:config:setup'];
152+
153+
// Call the astro:config:setup hook
154+
const astroUpdateConfig = vi.fn();
155+
astroConfigSetup({ updateConfig: astroUpdateConfig } as any);
156+
157+
// Verify it called updateConfig with vite plugins
158+
expect(astroUpdateConfig).toHaveBeenCalledWith(
159+
expect.objectContaining({
160+
vite: expect.objectContaining({
161+
plugins: expect.any(Array),
162+
}),
163+
})
164+
);
165+
});
166+
});

0 commit comments

Comments
 (0)