@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.
Files changed (32) hide show
  1. package/dist/styles/classes.json +1 -1
  2. package/dist/styles/ui.css +1 -1
  3. package/dist/templates/contents/themes/starter/tests/cypress/e2e/_selectors/auth.cy.ts +199 -0
  4. package/dist/templates/contents/themes/starter/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +104 -0
  5. package/dist/templates/contents/themes/starter/tests/cypress/e2e/_selectors/tasks.cy.ts +274 -0
  6. package/dist/templates/contents/themes/starter/tests/cypress/support/e2e.ts +36 -4
  7. package/dist/templates/contents/themes/starter/tests/cypress.config.ts +18 -15
  8. package/dist/templates/contents/themes/starter/tests/jest/__mocks__/jose.js +22 -0
  9. package/dist/templates/contents/themes/starter/tests/jest/__mocks__/next-server.js +56 -0
  10. package/dist/templates/contents/themes/starter/tests/jest/example.test.ts +87 -0
  11. package/dist/templates/contents/themes/starter/tests/jest/jest.config.cjs +90 -0
  12. package/dist/templates/contents/themes/starter/tests/jest/services/tasks.service.test.ts +547 -0
  13. package/dist/templates/contents/themes/starter/tests/jest/setup.ts +170 -0
  14. package/package.json +12 -12
  15. package/scripts/build/docs-registry.mjs +0 -0
  16. package/scripts/create-theme.mjs +0 -0
  17. package/scripts/deploy/release-version.mjs +0 -0
  18. package/scripts/deploy/vercel-deploy.mjs +0 -0
  19. package/scripts/dev/watch-plugins.mjs +0 -0
  20. package/scripts/maintenance/update-core.mjs +0 -0
  21. package/scripts/setup/npm-postinstall.mjs +0 -0
  22. package/scripts/setup/setup-claude.mjs +0 -0
  23. package/scripts/validation/check-imports.sh +0 -0
  24. package/templates/contents/themes/starter/tests/cypress/e2e/_selectors/auth.cy.ts +199 -0
  25. package/templates/contents/themes/starter/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +104 -0
  26. package/templates/contents/themes/starter/tests/cypress/e2e/_selectors/tasks.cy.ts +274 -0
  27. package/templates/contents/themes/starter/tests/jest/__mocks__/jose.js +22 -0
  28. package/templates/contents/themes/starter/tests/jest/__mocks__/next-server.js +56 -0
  29. package/templates/contents/themes/starter/tests/jest/example.test.ts +87 -0
  30. package/templates/contents/themes/starter/tests/jest/jest.config.cjs +90 -0
  31. package/templates/contents/themes/starter/tests/jest/services/tasks.service.test.ts +547 -0
  32. 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 theme-specific and used by scripts/cy.mjs.
5
- * Run with: NEXT_PUBLIC_ACTIVE_THEME=starter pnpm cy:open
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 5173)
22
- const port = process.env.PORT || 5173
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: core tests + theme tests
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 (shared across themes)
38
- supportFile: path.join(projectRoot, 'core/tests/cypress/support/e2e.ts'),
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 } = require('allure-cypress/reporter')
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
- require('@cypress/grep/src/plugin')(config)
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(`Narrations saved to: ${filepath}`)
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
+ }