@nextsparkjs/theme-default 0.1.0-beta.21 → 0.1.0-beta.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Jest Setup for Default Theme
3
+ *
4
+ * This file provides complete Jest setup for npm mode.
5
+ * It includes all necessary polyfills and mocks.
6
+ */
7
+
8
+ import '@testing-library/jest-dom'
9
+ import { TextEncoder, TextDecoder } from 'util'
10
+
11
+ // Polyfill TextEncoder/TextDecoder for jsdom
12
+ global.TextEncoder = TextEncoder
13
+ global.TextDecoder = TextDecoder as typeof global.TextDecoder
14
+
15
+ // Polyfill Web APIs for Next.js server components testing
16
+ class MockHeaders {
17
+ private _headers: Map<string, string> = new Map()
18
+
19
+ constructor(init?: HeadersInit) {
20
+ if (init) {
21
+ if (init instanceof MockHeaders) {
22
+ init._headers.forEach((value, key) => this._headers.set(key, value))
23
+ } else if (Array.isArray(init)) {
24
+ init.forEach(([key, value]) => this._headers.set(key.toLowerCase(), value))
25
+ } else {
26
+ Object.entries(init).forEach(([key, value]) => this._headers.set(key.toLowerCase(), value))
27
+ }
28
+ }
29
+ }
30
+
31
+ get(name: string) { return this._headers.get(name.toLowerCase()) || null }
32
+ set(name: string, value: string) { this._headers.set(name.toLowerCase(), value) }
33
+ has(name: string) { return this._headers.has(name.toLowerCase()) }
34
+ delete(name: string) { this._headers.delete(name.toLowerCase()) }
35
+ forEach(cb: (value: string, key: string) => void) { this._headers.forEach(cb) }
36
+ entries() { return this._headers.entries() }
37
+ keys() { return this._headers.keys() }
38
+ values() { return this._headers.values() }
39
+ }
40
+
41
+ class MockRequest {
42
+ url: string
43
+ method: string
44
+ headers: MockHeaders
45
+ private _body: any
46
+
47
+ constructor(input: string | URL, init?: RequestInit) {
48
+ this.url = typeof input === 'string' ? input : input.toString()
49
+ this.method = init?.method || 'GET'
50
+ this.headers = new MockHeaders(init?.headers as HeadersInit)
51
+ this._body = init?.body
52
+ }
53
+
54
+ async json() {
55
+ if (!this._body) return {}
56
+ return typeof this._body === 'string' ? JSON.parse(this._body) : this._body
57
+ }
58
+
59
+ async text() {
60
+ return this._body?.toString() || ''
61
+ }
62
+
63
+ clone() {
64
+ return new MockRequest(this.url, {
65
+ method: this.method,
66
+ headers: Object.fromEntries(this.headers.entries()),
67
+ body: this._body,
68
+ })
69
+ }
70
+ }
71
+
72
+ class MockResponse {
73
+ body: any
74
+ status: number
75
+ statusText: string
76
+ headers: MockHeaders
77
+ ok: boolean
78
+
79
+ constructor(body?: any, init?: ResponseInit) {
80
+ this.body = body
81
+ this.status = init?.status || 200
82
+ this.statusText = init?.statusText || 'OK'
83
+ this.headers = new MockHeaders(init?.headers as HeadersInit)
84
+ this.ok = this.status >= 200 && this.status < 300
85
+ }
86
+
87
+ async json() {
88
+ if (!this.body) return {}
89
+ return typeof this.body === 'string' ? JSON.parse(this.body) : this.body
90
+ }
91
+
92
+ async text() {
93
+ return this.body?.toString() || ''
94
+ }
95
+
96
+ clone() {
97
+ return new MockResponse(this.body, {
98
+ status: this.status,
99
+ statusText: this.statusText,
100
+ headers: Object.fromEntries(this.headers.entries()),
101
+ })
102
+ }
103
+
104
+ static json(data: any, init?: ResponseInit) {
105
+ return new MockResponse(JSON.stringify(data), {
106
+ ...init,
107
+ headers: { 'Content-Type': 'application/json', ...(init?.headers || {}) as object },
108
+ })
109
+ }
110
+ }
111
+
112
+ // Assign to global scope
113
+ global.Headers = MockHeaders as any
114
+ global.Request = MockRequest as any
115
+ global.Response = MockResponse as any
116
+
117
+ // Mock fetch
118
+ global.fetch = jest.fn().mockResolvedValue(new MockResponse('{}', { status: 200 }))
119
+
120
+ // Mock Web Crypto API
121
+ const crypto = require('crypto')
122
+ Object.defineProperty(global, 'crypto', {
123
+ value: {
124
+ getRandomValues: (arr: Uint8Array) => crypto.randomFillSync(arr),
125
+ randomUUID: () => crypto.randomUUID(),
126
+ subtle: {
127
+ digest: async (algorithm: string, data: BufferSource) => {
128
+ const hash = crypto.createHash(algorithm.toLowerCase().replace('-', ''))
129
+ hash.update(Buffer.from(data as ArrayBuffer))
130
+ return hash.digest().buffer
131
+ },
132
+ encrypt: jest.fn(),
133
+ decrypt: jest.fn(),
134
+ sign: jest.fn(),
135
+ verify: jest.fn(),
136
+ generateKey: jest.fn(),
137
+ importKey: jest.fn(),
138
+ exportKey: jest.fn(),
139
+ },
140
+ },
141
+ })
142
+
143
+ // Mock matchMedia for component tests with media queries
144
+ Object.defineProperty(window, 'matchMedia', {
145
+ writable: true,
146
+ value: jest.fn().mockImplementation((query) => ({
147
+ matches: false,
148
+ media: query,
149
+ onchange: null,
150
+ addListener: jest.fn(),
151
+ removeListener: jest.fn(),
152
+ addEventListener: jest.fn(),
153
+ removeEventListener: jest.fn(),
154
+ dispatchEvent: jest.fn(),
155
+ })),
156
+ })
157
+
158
+ // Mock ResizeObserver
159
+ global.ResizeObserver = jest.fn().mockImplementation(() => ({
160
+ observe: jest.fn(),
161
+ unobserve: jest.fn(),
162
+ disconnect: jest.fn(),
163
+ }))
164
+
165
+ // Mock IntersectionObserver
166
+ global.IntersectionObserver = jest.fn().mockImplementation(() => ({
167
+ observe: jest.fn(),
168
+ unobserve: jest.fn(),
169
+ disconnect: jest.fn(),
170
+ }))
@@ -1,81 +0,0 @@
1
- /**
2
- * Jest Configuration for Default Theme
3
- *
4
- * This config is automatically loaded by the theme test runner.
5
- *
6
- * Usage:
7
- * pnpm test:theme # Run theme tests
8
- * pnpm test:theme:watch # Watch mode
9
- * pnpm test:theme:coverage # With coverage
10
- */
11
-
12
- import type { Config } from 'jest'
13
-
14
- const config: Config = {
15
- displayName: 'theme-default',
16
- rootDir: '../../../../..',
17
-
18
- // Test file patterns
19
- testMatch: [
20
- '<rootDir>/contents/themes/default/tests/jest/**/*.{test,spec}.{js,ts,tsx}',
21
- ],
22
- testPathIgnorePatterns: [
23
- '<rootDir>/node_modules/',
24
- '<rootDir>/.next/',
25
- ],
26
-
27
- // Preset and environment
28
- preset: 'ts-jest',
29
- testEnvironment: 'jsdom',
30
-
31
- // Module resolution (aliases @/)
32
- // IMPORTANT: More specific patterns MUST come before generic ones
33
- moduleNameMapper: {
34
- '^@nextsparkjs/core/(.*)$': '<rootDir>/packages/core/$1',
35
- '^@/contents/(.*)$': '<rootDir>/contents/$1',
36
- '^@/entities/(.*)$': '<rootDir>/contents/entities/$1',
37
- '^@/plugins/(.*)$': '<rootDir>/contents/plugins/$1',
38
- '^@/themes/(.*)$': '<rootDir>/contents/themes/$1',
39
- '^@/(.*)$': '<rootDir>/$1',
40
- 'next/server': '<rootDir>/packages/core/tests/jest/__mocks__/next-server.js',
41
- '^jose$': '<rootDir>/packages/core/tests/jest/__mocks__/jose.js',
42
- '^jose/(.*)$': '<rootDir>/packages/core/tests/jest/__mocks__/jose.js',
43
- },
44
-
45
- // Setup files
46
- setupFilesAfterEnv: ['<rootDir>/packages/core/tests/setup.ts'],
47
-
48
- // Transform configuration
49
- transform: {
50
- '^.+\\.(ts|tsx)$': [
51
- 'ts-jest',
52
- {
53
- tsconfig: 'tsconfig.test.json',
54
- },
55
- ],
56
- },
57
-
58
- // Transform ignore patterns
59
- transformIgnorePatterns: [
60
- 'node_modules/(?!(uncrypto|better-auth|@noble|.*jose.*|remark.*|unified.*|.*\\.mjs$))',
61
- 'node_modules/\\.pnpm/(?!(.*uncrypto.*|.*better-auth.*|.*@noble.*|.*jose.*|.*remark.*|.*unified.*|.*\\.mjs$))',
62
- ],
63
-
64
- // File extensions
65
- moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
66
-
67
- // Test timeout
68
- testTimeout: 10000,
69
-
70
- // Verbose output
71
- verbose: true,
72
-
73
- // Force exit after tests complete
74
- forceExit: true,
75
-
76
- // Coverage output directory
77
- coverageDirectory: '<rootDir>/contents/themes/default/tests/jest/coverage',
78
- coverageReporters: ['text', 'lcov', 'html'],
79
- }
80
-
81
- export default config