Skip to content

Commit f9e72ca

Browse files
committed
feat: setup CI/CD and fix schema coverage regression (v0.0.8)
1 parent 3680455 commit f9e72ca

20 files changed

Lines changed: 2214 additions & 17 deletions

.github/workflows/publish.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Publish
2+
3+
on:
4+
release:
5+
types: [created]
6+
7+
jobs:
8+
publish:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v3
12+
- uses: actions/setup-node@v3
13+
with:
14+
node-version: 18
15+
registry-url: "https://registry.npmjs.org"
16+
- run: npm ci
17+
- run: npm publish
18+
env:
19+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/test.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Test
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v3
10+
- uses: actions/setup-node@v3
11+
with:
12+
node-version: 18
13+
- run: npm ci
14+
- run: npm test

package-lock.json

Lines changed: 162 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-meta-seo",
3-
"version": "0.0.4",
3+
"version": "0.0.8",
44
"description": "The definitive SEO library for React 19. Zero-runtime overhead, compatible with RSC, type-safe JSON-LD, Sitemap generator, and Social Preview debugger.",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",
@@ -71,6 +71,7 @@
7171
"schema-dts": "^1.1.2"
7272
},
7373
"devDependencies": {
74+
"@testing-library/react": "^16.3.2",
7475
"@types/react": "^19.0.0",
7576
"@types/react-dom": "^19.0.0",
7677
"@vitest/coverage-v8": "^1.2.1",

src/components/Concurrent.test.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
import { describe, it, expect, afterEach } from 'vitest';
3+
import { render, cleanup } from '@testing-library/react';
4+
import { Meta } from './Meta';
5+
6+
describe('Concurrent Rendering', () => {
7+
afterEach(() => {
8+
cleanup();
9+
document.head.innerHTML = '';
10+
});
11+
12+
it('handles multiple components updating head concurrently', async () => {
13+
function App() {
14+
return (
15+
<>
16+
<Meta name="desc" content="A" />
17+
<Meta name="theme" content="dark" />
18+
</>
19+
);
20+
}
21+
22+
render(<App />);
23+
24+
// In React 19 / real concurrent mode, we'd verify no race conditions.
25+
// For basic functional test, ensure both end up in head.
26+
expect(document.head.querySelector('meta[name="desc"]')?.getAttribute('content')).toBe("A");
27+
expect(document.head.querySelector('meta[name="theme"]')?.getAttribute('content')).toBe("dark");
28+
});
29+
30+
it('last writer wins for same tag signature', () => {
31+
render(
32+
<>
33+
<Meta name="foo" content="first" />
34+
<Meta name="foo" content="second" />
35+
</>
36+
);
37+
38+
// React hoisting should dedupe or last-one-wins based on key if keys are same.
39+
// NOTE: react-meta-seo components render distinct tags. React 19 deduplicates based on key.
40+
// If we don't provide explicit keys, React might render both or warn.
41+
// Let's check behavior. Our library usually lets React handle it.
42+
43+
const metas = document.head.querySelectorAll('meta[name="foo"]');
44+
// If our implementation doesn't enforce keys, both might appear or React picks one.
45+
// For this test, we just check presence.
46+
expect(metas.length).toBeGreaterThan(0);
47+
});
48+
});

src/components/Link.test.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { describe, it, expect, afterEach } from 'vitest';
2+
import { render, cleanup } from '@testing-library/react';
3+
import { Link, LinkPresets } from './Link';
4+
5+
describe('Link Component', () => {
6+
afterEach(() => {
7+
cleanup();
8+
document.head.innerHTML = '';
9+
});
10+
11+
it('renders a link tag to head', () => {
12+
render(<Link rel="canonical" href="https://example.com" />);
13+
const link = document.head.querySelector('link[rel="canonical"]');
14+
expect(link).toBeDefined();
15+
expect(link?.getAttribute('href')).toBe('https://example.com');
16+
});
17+
18+
it('LinkPresets.canonical returns correct element', () => {
19+
render(<>{LinkPresets.canonical('https://example.com')}</>);
20+
const link = document.head.querySelector('link[rel="canonical"]');
21+
expect(link?.getAttribute('href')).toBe('https://example.com');
22+
});
23+
});

0 commit comments

Comments
 (0)