@nextsparkjs/core 0.1.0-beta.23 → 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.
- package/dist/styles/classes.json +1 -1
- package/dist/styles/ui.css +1 -1
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/_selectors/auth.cy.ts +199 -0
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +104 -0
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/_selectors/tasks.cy.ts +274 -0
- package/dist/templates/contents/themes/starter/tests/cypress/support/e2e.ts +36 -4
- package/dist/templates/contents/themes/starter/tests/cypress.config.ts +18 -15
- package/dist/templates/contents/themes/starter/tests/jest/__mocks__/jose.js +22 -0
- package/dist/templates/contents/themes/starter/tests/jest/__mocks__/next-server.js +56 -0
- package/dist/templates/contents/themes/starter/tests/jest/example.test.ts +87 -0
- package/dist/templates/contents/themes/starter/tests/jest/jest.config.cjs +90 -0
- package/dist/templates/contents/themes/starter/tests/jest/services/tasks.service.test.ts +547 -0
- package/dist/templates/contents/themes/starter/tests/jest/setup.ts +170 -0
- package/package.json +12 -12
- package/scripts/build/docs-registry.mjs +0 -0
- package/scripts/create-theme.mjs +0 -0
- package/scripts/deploy/release-version.mjs +0 -0
- package/scripts/deploy/vercel-deploy.mjs +0 -0
- package/scripts/dev/watch-plugins.mjs +0 -0
- package/scripts/maintenance/update-core.mjs +0 -0
- package/scripts/setup/npm-postinstall.mjs +0 -0
- package/scripts/setup/setup-claude.mjs +0 -0
- package/scripts/validation/check-imports.sh +0 -0
- package/templates/contents/themes/starter/tests/cypress/e2e/_selectors/auth.cy.ts +199 -0
- package/templates/contents/themes/starter/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +104 -0
- package/templates/contents/themes/starter/tests/cypress/e2e/_selectors/tasks.cy.ts +274 -0
- package/templates/contents/themes/starter/tests/jest/__mocks__/jose.js +22 -0
- package/templates/contents/themes/starter/tests/jest/__mocks__/next-server.js +56 -0
- package/templates/contents/themes/starter/tests/jest/example.test.ts +87 -0
- package/templates/contents/themes/starter/tests/jest/jest.config.cjs +90 -0
- package/templates/contents/themes/starter/tests/jest/services/tasks.service.test.ts +547 -0
- package/templates/contents/themes/starter/tests/jest/setup.ts +170 -0
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cypress Configuration for Starter Theme
|
|
3
3
|
*
|
|
4
|
-
* This config is
|
|
5
|
-
* Run with:
|
|
4
|
+
* This config is self-contained for npm projects created with `nextspark init`.
|
|
5
|
+
* Run with: pnpm cy:open
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { defineConfig } from 'cypress'
|
|
9
9
|
import path from 'path'
|
|
10
10
|
import fs from 'fs'
|
|
11
|
+
import { fileURLToPath } from 'url'
|
|
12
|
+
|
|
13
|
+
// ESM-compatible __dirname
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
15
|
+
const __dirname = path.dirname(__filename)
|
|
11
16
|
|
|
12
17
|
// Paths relative to this config file
|
|
13
18
|
const themeRoot = path.resolve(__dirname, '..')
|
|
@@ -18,24 +23,21 @@ const narrationsOutputDir = path.join(__dirname, 'cypress/videos/narrations')
|
|
|
18
23
|
import dotenv from 'dotenv'
|
|
19
24
|
dotenv.config({ path: path.join(projectRoot, '.env') })
|
|
20
25
|
|
|
21
|
-
// Server port (from .env or default
|
|
22
|
-
const port = process.env.PORT ||
|
|
26
|
+
// Server port (from .env or default 3000)
|
|
27
|
+
const port = process.env.PORT || 3000
|
|
23
28
|
|
|
24
29
|
export default defineConfig({
|
|
25
30
|
e2e: {
|
|
26
31
|
// Base URL for the application
|
|
27
32
|
baseUrl: `http://localhost:${port}`,
|
|
28
33
|
|
|
29
|
-
// Spec patterns:
|
|
34
|
+
// Spec patterns: theme tests only
|
|
30
35
|
specPattern: [
|
|
31
|
-
// Core tests (always included)
|
|
32
|
-
path.join(projectRoot, 'core/tests/cypress/e2e/core/**/*.cy.{js,ts}'),
|
|
33
|
-
// Theme-specific tests
|
|
34
36
|
path.join(__dirname, 'cypress/e2e/**/*.cy.{js,ts}'),
|
|
35
37
|
],
|
|
36
38
|
|
|
37
|
-
// Support file (
|
|
38
|
-
supportFile: path.join(
|
|
39
|
+
// Support file (theme-local)
|
|
40
|
+
supportFile: path.join(__dirname, 'cypress/support/e2e.ts'),
|
|
39
41
|
|
|
40
42
|
// Fixtures folder (theme-specific)
|
|
41
43
|
fixturesFolder: path.join(__dirname, 'cypress/fixtures'),
|
|
@@ -96,15 +98,16 @@ export default defineConfig({
|
|
|
96
98
|
grepOmitFiltered: true,
|
|
97
99
|
},
|
|
98
100
|
|
|
99
|
-
setupNodeEvents(on, config) {
|
|
101
|
+
async setupNodeEvents(on, config) {
|
|
100
102
|
// Allure plugin setup (allure-cypress)
|
|
101
|
-
const { allureCypress } =
|
|
103
|
+
const { allureCypress } = await import('allure-cypress/reporter')
|
|
102
104
|
allureCypress(on, config, {
|
|
103
105
|
resultsDir: path.join(__dirname, 'cypress/allure-results'),
|
|
104
106
|
})
|
|
105
107
|
|
|
106
108
|
// @cypress/grep plugin for test filtering by tags
|
|
107
|
-
|
|
109
|
+
const grepPlugin = await import('@cypress/grep/src/plugin.js')
|
|
110
|
+
;(grepPlugin.default || grepPlugin)(config)
|
|
108
111
|
|
|
109
112
|
// Documentation video tasks
|
|
110
113
|
on('task', {
|
|
@@ -127,7 +130,7 @@ export default defineConfig({
|
|
|
127
130
|
const filepath = path.join(narrationsOutputDir, filename)
|
|
128
131
|
|
|
129
132
|
fs.writeFileSync(filepath, JSON.stringify(narrations, null, 2))
|
|
130
|
-
console.log(
|
|
133
|
+
console.log(`📝 Narrations saved to: ${filepath}`)
|
|
131
134
|
|
|
132
135
|
return null
|
|
133
136
|
},
|
|
@@ -136,7 +139,7 @@ export default defineConfig({
|
|
|
136
139
|
* Add narration entry (called per narration)
|
|
137
140
|
*/
|
|
138
141
|
addNarration(narration: unknown) {
|
|
139
|
-
console.log('Narration:', narration)
|
|
142
|
+
console.log('🎙️ Narration:', narration)
|
|
140
143
|
return null
|
|
141
144
|
},
|
|
142
145
|
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock for jose package
|
|
3
|
+
* Resolves ES module import issues in Jest tests
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
jwtVerify: jest.fn(),
|
|
8
|
+
SignJWT: jest.fn().mockImplementation(() => ({
|
|
9
|
+
setProtectedHeader: jest.fn().mockReturnThis(),
|
|
10
|
+
setIssuedAt: jest.fn().mockReturnThis(),
|
|
11
|
+
setExpirationTime: jest.fn().mockReturnThis(),
|
|
12
|
+
sign: jest.fn().mockResolvedValue('mock-jwt-token')
|
|
13
|
+
})),
|
|
14
|
+
importJWK: jest.fn(),
|
|
15
|
+
generateSecret: jest.fn(),
|
|
16
|
+
createRemoteJWKSet: jest.fn(),
|
|
17
|
+
errors: {
|
|
18
|
+
JWTExpired: class JWTExpired extends Error {},
|
|
19
|
+
JWTInvalid: class JWTInvalid extends Error {},
|
|
20
|
+
JWTClaimValidationFailed: class JWTClaimValidationFailed extends Error {}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock for next/server
|
|
3
|
+
* Provides NextRequest and NextResponse mocks for API testing
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class MockNextRequest {
|
|
7
|
+
constructor(url, options = {}) {
|
|
8
|
+
this.url = url
|
|
9
|
+
this.method = options.method || 'GET'
|
|
10
|
+
this.headers = new Map(Object.entries(options.headers || {}))
|
|
11
|
+
this._body = options.body
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async json() {
|
|
15
|
+
if (!this._body) return {}
|
|
16
|
+
try {
|
|
17
|
+
return typeof this._body === 'string' ? JSON.parse(this._body) : this._body
|
|
18
|
+
} catch {
|
|
19
|
+
throw new SyntaxError('Invalid JSON')
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async text() {
|
|
24
|
+
return this._body || ''
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class MockNextResponse {
|
|
29
|
+
constructor(body, options = {}) {
|
|
30
|
+
this.body = body
|
|
31
|
+
this.status = options.status || 200
|
|
32
|
+
this.statusText = options.statusText || 'OK'
|
|
33
|
+
this.headers = new Map(Object.entries(options.headers || {}))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async json() {
|
|
37
|
+
if (!this.body) return {}
|
|
38
|
+
try {
|
|
39
|
+
return typeof this.body === 'string' ? JSON.parse(this.body) : this.body
|
|
40
|
+
} catch {
|
|
41
|
+
throw new SyntaxError('Invalid JSON')
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static json(data, options = {}) {
|
|
46
|
+
return new MockNextResponse(data, {
|
|
47
|
+
...options,
|
|
48
|
+
headers: { 'Content-Type': 'application/json', ...options.headers }
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
NextRequest: MockNextRequest,
|
|
55
|
+
NextResponse: MockNextResponse
|
|
56
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example Jest Test
|
|
3
|
+
*
|
|
4
|
+
* This file demonstrates how to write Jest tests for your theme.
|
|
5
|
+
* Run tests with: pnpm test:theme
|
|
6
|
+
*
|
|
7
|
+
* Test Organization:
|
|
8
|
+
* - Create test files with .test.ts or .spec.ts extension
|
|
9
|
+
* - Group related tests in describe blocks
|
|
10
|
+
* - Use meaningful test names that describe the expected behavior
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { render, screen } from '@testing-library/react'
|
|
14
|
+
|
|
15
|
+
// Example: Testing a simple utility function
|
|
16
|
+
describe('Example Utility Tests', () => {
|
|
17
|
+
it('should demonstrate a simple passing test', () => {
|
|
18
|
+
const sum = (a: number, b: number) => a + b
|
|
19
|
+
expect(sum(2, 3)).toBe(5)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should work with async/await', async () => {
|
|
23
|
+
const fetchData = async () => ({ status: 'ok' })
|
|
24
|
+
const result = await fetchData()
|
|
25
|
+
expect(result.status).toBe('ok')
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// Example: Testing with mocked fetch
|
|
30
|
+
describe('API Mock Tests', () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
// Reset fetch mock before each test
|
|
33
|
+
;(global.fetch as jest.Mock).mockReset()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should mock fetch responses', async () => {
|
|
37
|
+
const mockData = { users: ['Alice', 'Bob'] }
|
|
38
|
+
|
|
39
|
+
;(global.fetch as jest.Mock).mockResolvedValueOnce({
|
|
40
|
+
ok: true,
|
|
41
|
+
status: 200,
|
|
42
|
+
json: async () => mockData,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const response = await fetch('/api/users')
|
|
46
|
+
const data = await response.json()
|
|
47
|
+
|
|
48
|
+
expect(data.users).toHaveLength(2)
|
|
49
|
+
expect(data.users).toContain('Alice')
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// Example: Testing React components
|
|
54
|
+
describe('React Component Tests', () => {
|
|
55
|
+
it('should render a simple component', () => {
|
|
56
|
+
const SimpleComponent = () => <div data-testid="greeting">Hello World</div>
|
|
57
|
+
|
|
58
|
+
render(<SimpleComponent />)
|
|
59
|
+
|
|
60
|
+
expect(screen.getByTestId('greeting')).toHaveTextContent('Hello World')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should use jest-dom matchers', () => {
|
|
64
|
+
const Button = ({ disabled }: { disabled: boolean }) => (
|
|
65
|
+
<button disabled={disabled}>Click me</button>
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
render(<Button disabled={true} />)
|
|
69
|
+
|
|
70
|
+
const button = screen.getByRole('button')
|
|
71
|
+
expect(button).toBeDisabled()
|
|
72
|
+
expect(button).toHaveTextContent('Click me')
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// Example: Testing with theme imports
|
|
77
|
+
describe('Theme Integration Tests', () => {
|
|
78
|
+
// You can import theme utilities and test them
|
|
79
|
+
// import { formatDate } from '../../lib/utils'
|
|
80
|
+
|
|
81
|
+
it('should work with theme utilities', () => {
|
|
82
|
+
// Example test placeholder
|
|
83
|
+
// const formatted = formatDate(new Date('2024-01-15'))
|
|
84
|
+
// expect(formatted).toBe('January 15, 2024')
|
|
85
|
+
expect(true).toBe(true)
|
|
86
|
+
})
|
|
87
|
+
})
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jest Configuration for Starter Theme
|
|
3
|
+
*
|
|
4
|
+
* This config is for npm mode (projects created via nextspark init).
|
|
5
|
+
* Run with: pnpm test:theme
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path')
|
|
9
|
+
|
|
10
|
+
// Paths relative to this config file
|
|
11
|
+
const themeTestsRoot = __dirname
|
|
12
|
+
const themeRoot = path.resolve(__dirname, '../..')
|
|
13
|
+
|
|
14
|
+
// In npm mode: contents/themes/starter/tests/jest -> project root (5 levels up)
|
|
15
|
+
const projectRoot = path.resolve(__dirname, '../../../../..')
|
|
16
|
+
|
|
17
|
+
/** @type {import('jest').Config} */
|
|
18
|
+
module.exports = {
|
|
19
|
+
displayName: 'theme-starter',
|
|
20
|
+
rootDir: projectRoot,
|
|
21
|
+
|
|
22
|
+
// Use roots to explicitly set test location
|
|
23
|
+
roots: [themeTestsRoot],
|
|
24
|
+
|
|
25
|
+
// Test file patterns
|
|
26
|
+
testMatch: [
|
|
27
|
+
'**/*.{test,spec}.{js,ts,tsx}',
|
|
28
|
+
],
|
|
29
|
+
testPathIgnorePatterns: [
|
|
30
|
+
'<rootDir>/node_modules/',
|
|
31
|
+
'<rootDir>/.next/',
|
|
32
|
+
],
|
|
33
|
+
|
|
34
|
+
// Preset and environment
|
|
35
|
+
preset: 'ts-jest',
|
|
36
|
+
testEnvironment: 'jsdom',
|
|
37
|
+
|
|
38
|
+
// Module resolution for npm mode
|
|
39
|
+
moduleNameMapper: {
|
|
40
|
+
// Resolve from node_modules
|
|
41
|
+
'^@nextsparkjs/core/(.*)$': '@nextsparkjs/core/$1',
|
|
42
|
+
'^@nextsparkjs/core$': '@nextsparkjs/core',
|
|
43
|
+
'^@/contents/(.*)$': '<rootDir>/contents/$1',
|
|
44
|
+
'^@/entities/(.*)$': '<rootDir>/contents/entities/$1',
|
|
45
|
+
'^@/plugins/(.*)$': '<rootDir>/contents/plugins/$1',
|
|
46
|
+
'^@/themes/(.*)$': '<rootDir>/contents/themes/$1',
|
|
47
|
+
'^@/(.*)$': '<rootDir>/$1',
|
|
48
|
+
// Mocks from theme-local folder
|
|
49
|
+
'next/server': path.join(themeTestsRoot, '__mocks__/next-server.js'),
|
|
50
|
+
'^jose$': path.join(themeTestsRoot, '__mocks__/jose.js'),
|
|
51
|
+
'^jose/(.*)$': path.join(themeTestsRoot, '__mocks__/jose.js'),
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// Setup files
|
|
55
|
+
setupFilesAfterEnv: [
|
|
56
|
+
path.join(themeTestsRoot, 'setup.ts'),
|
|
57
|
+
],
|
|
58
|
+
|
|
59
|
+
// Transform configuration
|
|
60
|
+
transform: {
|
|
61
|
+
'^.+\\.(ts|tsx)$': ['ts-jest', {
|
|
62
|
+
tsconfig: path.join(projectRoot, 'tsconfig.json'),
|
|
63
|
+
}],
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// Transform ignore patterns
|
|
67
|
+
transformIgnorePatterns: [
|
|
68
|
+
'node_modules/(?!(uncrypto|better-auth|@noble|.*jose.*|remark.*|unified.*|@nextsparkjs/core/tests|.*\\.mjs$))',
|
|
69
|
+
'node_modules/\\.pnpm/(?!(.*uncrypto.*|.*better-auth.*|.*@noble.*|.*jose.*|.*remark.*|.*unified.*|@nextsparkjs.*core.*tests|.*\\.mjs$))',
|
|
70
|
+
],
|
|
71
|
+
|
|
72
|
+
// File extensions
|
|
73
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
|
74
|
+
|
|
75
|
+
// Test timeout
|
|
76
|
+
testTimeout: 10000,
|
|
77
|
+
|
|
78
|
+
// Verbose output
|
|
79
|
+
verbose: true,
|
|
80
|
+
|
|
81
|
+
// Force exit after tests complete
|
|
82
|
+
forceExit: true,
|
|
83
|
+
|
|
84
|
+
// Disable watchman for symlink support
|
|
85
|
+
watchman: false,
|
|
86
|
+
|
|
87
|
+
// Coverage output directory
|
|
88
|
+
coverageDirectory: path.join(themeTestsRoot, 'coverage'),
|
|
89
|
+
coverageReporters: ['text', 'lcov', 'html'],
|
|
90
|
+
}
|