@stone-js/starters 0.8.7 → 0.8.9

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 (74) hide show
  1. package/README.md +2 -2
  2. package/basic-react-declarative/app/Application.tsx +0 -2
  3. package/basic-react-declarative/package.json +7 -7
  4. package/basic-react-declarative/public/favicon.svg +16 -0
  5. package/basic-react-declarative/tests/Application.spec.ts +25 -100
  6. package/basic-react-imperative/app/Application.tsx +2 -17
  7. package/basic-react-imperative/package.json +7 -7
  8. package/basic-react-imperative/public/favicon.svg +16 -0
  9. package/basic-react-imperative/tests/Application.spec.ts +25 -86
  10. package/basic-service-declarative/app/Application.ts +0 -2
  11. package/basic-service-declarative/package.json +6 -6
  12. package/basic-service-declarative/tests/Application.spec.ts +20 -53
  13. package/basic-service-imperative/app/Application.ts +2 -14
  14. package/basic-service-imperative/package.json +6 -6
  15. package/basic-service-imperative/tests/Application.spec.ts +19 -44
  16. package/continuum-showcase/package.json +11 -10
  17. package/continuum-showcase/public/favicon.svg +16 -0
  18. package/continuum-showcase/stone.config.mjs +2 -2
  19. package/continuum-showcase/tests/application.spec.ts +30 -0
  20. package/full-react-declarative/app/Application.ts +0 -4
  21. package/full-react-declarative/package.json +12 -12
  22. package/full-react-declarative/public/favicon.svg +16 -0
  23. package/full-react-declarative/stone.config.mjs +2 -2
  24. package/full-react-declarative/tests/application.spec.ts +30 -0
  25. package/full-react-imperative/app/Application.ts +1 -3
  26. package/full-react-imperative/package.json +12 -12
  27. package/full-react-imperative/public/favicon.svg +16 -0
  28. package/full-react-imperative/stone.config.mjs +2 -2
  29. package/full-react-imperative/tests/application.spec.ts +30 -0
  30. package/full-service-declarative/app/Application.ts +5 -2
  31. package/full-service-declarative/app/configurations/AppConfiguration.ts +1 -3
  32. package/full-service-declarative/package.json +13 -12
  33. package/full-service-declarative/stone.config.mjs +2 -2
  34. package/full-service-declarative/tests/application.spec.ts +30 -0
  35. package/full-service-imperative/app/Application.ts +8 -2
  36. package/full-service-imperative/app/configurations/AppConfiguration.ts +1 -3
  37. package/full-service-imperative/package.json +13 -12
  38. package/full-service-imperative/stone.config.mjs +2 -2
  39. package/full-service-imperative/tests/application.spec.ts +30 -0
  40. package/package.json +1 -1
  41. package/standard-react-declarative/package.json +11 -10
  42. package/standard-react-declarative/public/favicon.svg +16 -0
  43. package/standard-react-declarative/tests/application.spec.ts +30 -0
  44. package/standard-react-imperative/package.json +11 -10
  45. package/standard-react-imperative/public/favicon.svg +16 -0
  46. package/standard-react-imperative/tests/application.spec.ts +30 -0
  47. package/standard-service-declarative/package.json +9 -8
  48. package/standard-service-declarative/tests/Application.spec.ts +22 -94
  49. package/standard-service-imperative/package.json +9 -8
  50. package/standard-service-imperative/tests/Application.spec.ts +22 -78
  51. package/basic-react-declarative/vitest.config.ts +0 -24
  52. package/basic-react-imperative/vitest.config.ts +0 -24
  53. package/basic-service-declarative/vitest.config.ts +0 -24
  54. package/basic-service-imperative/vitest.config.ts +0 -24
  55. package/continuum-showcase/tests/HomePage.spec.tsx +0 -41
  56. package/continuum-showcase/vitest.config.ts +0 -31
  57. package/full-react-declarative/tests/AppLayout.spec.ts +0 -51
  58. package/full-react-declarative/tests/HomePage.spec.ts +0 -38
  59. package/full-react-declarative/vitest.config.ts +0 -24
  60. package/full-react-imperative/tests/HomePage.spec.ts +0 -45
  61. package/full-react-imperative/tests/LayoutHeader.spec.ts +0 -39
  62. package/full-react-imperative/vitest.config.ts +0 -24
  63. package/full-service-declarative/tests/PostService.spec.ts +0 -56
  64. package/full-service-declarative/tests/WelcomeEventHandler.spec.ts +0 -54
  65. package/full-service-declarative/vitest.config.ts +0 -24
  66. package/full-service-imperative/tests/PostService.spec.ts +0 -47
  67. package/full-service-imperative/tests/WelcomeEventHandler.spec.ts +0 -31
  68. package/full-service-imperative/vitest.config.ts +0 -24
  69. package/standard-react-declarative/tests/WelcomePage.spec.ts +0 -71
  70. package/standard-react-declarative/vitest.config.ts +0 -24
  71. package/standard-react-imperative/tests/WelcomePage.spec.ts +0 -53
  72. package/standard-react-imperative/vitest.config.ts +0 -24
  73. package/standard-service-declarative/vitest.config.ts +0 -24
  74. package/standard-service-imperative/vitest.config.ts +0 -24
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![License: MIT](https://img.shields.io/npm/l/@stone-js/starters)](https://opensource.org/licenses/MIT)
4
4
  [![Maintenance](https://img.shields.io/maintenance/yes/2026)](https://stonejs.dev)
5
- [![Used by Stone CLI](https://img.shields.io/badge/Used%20by-Stone%20CLI-blue)](https://github.com/stone-foundation/stone-js-cli)
5
+ [![Used by Stone CLI](https://img.shields.io/badge/Used%20by-Stone%20CLI-blue)](https://github.com/stone-foundation/stone-js-framework)
6
6
 
7
7
  This repository contains official **starter templates** for Stone.js applications.
8
8
 
@@ -98,4 +98,4 @@ Explore the full documentation: [https://stonejs.dev](https://stonejs.dev)
98
98
 
99
99
  ## Contributing
100
100
 
101
- See [Contributing Guide](https://github.com/stone-foundation/stone-js-starters/blob/main/CONTRIBUTING.md)
101
+ See [Contributing Guide](https://github.com/stone-foundation/stone-js-framework/blob/main/CONTRIBUTING.md)
@@ -1,6 +1,5 @@
1
1
  import { JSX } from 'react'
2
2
  import { Browser } from '@stone-js/browser-adapter'
3
- import { NodeConsole } from '@stone-js/node-cli-adapter'
4
3
  import { ILogger, LogLevel, Promiseable, StoneApp } from '@stone-js/core'
5
4
  import { ReactIncomingEvent, UseReact, HeadContext, IPage, PageHeadContext, PageRenderContext } from '@stone-js/use-react'
6
5
 
@@ -15,7 +14,6 @@ import { ReactIncomingEvent, UseReact, HeadContext, IPage, PageHeadContext, Page
15
14
  */
16
15
  @Browser()
17
16
  @UseReact()
18
- @NodeConsole()
19
17
  @StoneApp({ logger: { level: LogLevel.INFO } })
20
18
  export class Application implements IPage<ReactIncomingEvent> {
21
19
  /**
@@ -14,22 +14,22 @@
14
14
  "build": "stone build",
15
15
  "preview": "stone preview",
16
16
  "build:ssr": "stone build --ssr",
17
- "test": "vitest run",
18
- "test:cvg": "npm run test -- --coverage"
17
+ "test": "stone test",
18
+ "test:cvg": "stone test --coverage"
19
19
  },
20
20
  "dependencies": {
21
21
  "react": "^19.0.0",
22
22
  "react-dom": "^19.0.0",
23
- "@stone-js/core": "^0.8.7",
24
- "@stone-js/use-react": "^0.8.7",
25
- "@stone-js/browser-adapter": "^0.8.7",
26
- "@stone-js/node-cli-adapter": "^0.8.7"
23
+ "@stone-js/core": "^0.8.9",
24
+ "@stone-js/use-react": "^0.8.9",
25
+ "@stone-js/browser-adapter": "^0.8.9"
27
26
  },
28
27
  "devDependencies": {
29
28
  "@babel/plugin-proposal-decorators": "^7.25.9",
30
29
  "@babel/preset-env": "^7.26.9",
31
30
  "@babel/preset-typescript": "^7.27.0",
32
- "@stone-js/cli": "^0.8.7",
31
+ "@stone-js/cli": "^0.8.9",
32
+ "@stone-js/testing": "^0.8.9",
33
33
  "@types/node": "^24.0.7",
34
34
  "@types/react": "^19.0.7",
35
35
  "@types/react-dom": "^19.0.3",
@@ -0,0 +1,16 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" width="96" height="96" role="img" aria-label="Stone.js">
2
+ <title>Stone.js</title>
3
+ <style>
4
+ .ink { stroke: #1B1613; }
5
+ @media (prefers-color-scheme: dark) { .ink { stroke: #EFE8DC; } }
6
+ </style>
7
+ <defs>
8
+ <linearGradient id="braise" gradientUnits="userSpaceOnUse" x1="22" y1="14" x2="74" y2="26.1">
9
+ <stop offset="0" stop-color="#FFC46B" />
10
+ <stop offset="1" stop-color="#FF5A1F" />
11
+ </linearGradient>
12
+ </defs>
13
+ <path class="ink" d="M 79.96 36.4 A 34 34 0 0 1 53.9 81.5" fill="none" stroke-width="11" stroke-linecap="round" opacity=".85" />
14
+ <path class="ink" d="M 42.1 81.5 A 34 34 0 0 1 16.05 36.4" fill="none" stroke-width="11" stroke-linecap="round" opacity=".85" />
15
+ <path d="M 22 26.1 A 34 34 0 0 1 74 26.1" fill="none" stroke="url(#braise)" stroke-width="11" stroke-linecap="round" />
16
+ </svg>
@@ -1,105 +1,30 @@
1
- import { ILogger } from '@stone-js/core'
2
- import { Application } from '../app/Application'
3
- import { renderToString } from 'react-dom/server'
4
- import { ReactIncomingEvent } from '@stone-js/use-react'
5
-
6
- // We must mock decorators to lighten the test environment
7
- vi.mock('@stone-js/core', async (importOriginal) => {
8
- const actual: any = await importOriginal()
9
- return {
10
- ...actual,
11
- StoneApp: vi.fn(() => vi.fn()),
12
- }
13
- })
14
-
15
- // We must mock decorators to lighten the test environment
16
- vi.mock('@stone-js/node-cli-adapter', async (importOriginal) => {
17
- const actual: any = await importOriginal()
18
- return {
19
- ...actual,
20
- NodeConsole: vi.fn(() => vi.fn()),
21
- }
22
- })
23
-
24
- // We must mock decorators to lighten the test environment
25
- vi.mock('@stone-js/browser-adapter', async (importOriginal) => {
26
- const actual: any = await importOriginal()
27
- return {
28
- ...actual,
29
- Browser: vi.fn(() => vi.fn()),
30
- }
31
- })
32
-
33
- // We must mock decorators to lighten the test environment
34
- vi.mock('@stone-js/use-react', async (importOriginal) => {
35
- const actual: any = await importOriginal()
36
- return {
37
- ...actual,
38
- UseReact: vi.fn(() => vi.fn()),
39
- }
40
- })
41
-
42
- describe('Application', () => {
43
- let app: Application
44
- let mockedLogger: ILogger
45
-
46
- beforeEach(() => {
47
- mockedLogger = {
48
- info: vi.fn(),
49
- } as unknown as ILogger
50
-
51
- app = new Application({ logger: mockedLogger })
52
- })
53
-
54
- it('should create an application instance', () => {
55
- // Assert
56
- expect(app).toBeInstanceOf(Application)
1
+ import { createTestApp, makeIncomingHttpEvent } from '@stone-js/testing'
2
+
3
+ /**
4
+ * The whole application, booted in memory and asked a real question.
5
+ *
6
+ * Nothing is mocked and nothing is listed: `createTestApp()` discovers `app/**`, and the event goes
7
+ * through the same kernel production runs. If this passes the application works; if it fails the
8
+ * application is broken. That is the only kind of test worth shipping in a starter — the previous one
9
+ * stubbed out the framework's own decorators, which meant it could pass while nothing worked.
10
+ */
11
+ describe('Pages', () => {
12
+ it('renders the home page, data included', async () => {
13
+ const app = await createTestApp()
14
+
15
+ const response = await app.send(makeIncomingHttpEvent({ method: 'GET', url: '/?name=Ada' }))
16
+
17
+ expect(response.statusCode).toBe(200)
18
+ // A page is a handler, so a rendered page is a response whose body is HTML. Query that HTML with
19
+ // whatever you already use (happy-dom, jsdom, Testing Library): none is bundled here.
20
+ expect(response.html()).toContain('Ada')
57
21
  })
58
22
 
59
- it('get head values', async () => {
60
- // Arrange
61
- const event = { get: () => 'World' } as unknown as ReactIncomingEvent
23
+ it('renders without a name', async () => {
24
+ const app = await createTestApp()
62
25
 
63
- // Act
64
- const head = await app.head({ event })
26
+ const response = await app.send(makeIncomingHttpEvent({ method: 'GET', url: '/' }))
65
27
 
66
- // Assert
67
- expect(head).toHaveProperty('metas')
68
- expect(head.title).toContain('Welcome to Stone.js')
69
- expect(head.title).toContain('World')
70
- expect(head).toHaveProperty('description')
28
+ expect(response.statusCode).toBe(200)
71
29
  })
72
-
73
- it('should handle incoming events', () => {
74
- // Arrange
75
- const expectedMessage = 'Hello World!'
76
- const event = { get: () => 'World' } as unknown as ReactIncomingEvent
77
-
78
- // Act
79
- const response = app.handle(event) as { message: string }
80
-
81
- // Assert
82
- expect(response.message).toBe(expectedMessage)
83
- expect(mockedLogger.info).toHaveBeenCalledWith(expectedMessage)
84
- })
85
-
86
- it('should render the message', () => {
87
- // Arrange
88
- const message = 'Hello World!'
89
-
90
- // Act
91
- const response = renderToString(app.render({ data: { message } } as any))
92
-
93
- // Assert
94
- expect(response).toContain(message)
95
- })
96
-
97
- it('should render the Stone.js logo', () => {
98
- // Act
99
- const response = renderToString(app.render({ data: { message: 'Hello World!' } } as any))
100
-
101
- // Assert
102
- expect(response).toContain('/logo.svg')
103
- expect(response).toContain('alt="Stone.js"')
104
- })
105
- })
30
+ })
@@ -1,7 +1,6 @@
1
1
  import { JSX } from 'react'
2
2
  import { browserAdapterBlueprint } from '@stone-js/browser-adapter'
3
- import { defineConfig, IBlueprint, ILogger, isNotEmpty, Promiseable } from '@stone-js/core'
4
- import { defineCommand, FactoryCommandHandler, NODE_CONSOLE_PLATFORM, nodeConsoleAdapterBlueprint } from '@stone-js/node-cli-adapter'
3
+ import { ILogger, Promiseable } from '@stone-js/core'
5
4
  import { defineStoneReactApp, HeadContext, IPage, PageHeadContext, PageRenderContext, ReactIncomingEvent } from '@stone-js/use-react'
6
5
 
7
6
  /**
@@ -73,23 +72,9 @@ export const FactoryHandler = ({ logger }: AppOptions): IPage<ReactIncomingEvent
73
72
  export const Application = defineStoneReactApp(
74
73
  FactoryHandler,
75
74
  { debug: true, isFactory: true },
76
- [browserAdapterBlueprint, nodeConsoleAdapterBlueprint]
75
+ [browserAdapterBlueprint]
77
76
  )
78
77
 
79
- /**
80
- * Application configuration.
81
- */
82
- export const AppConfig = defineConfig({
83
- afterConfigure (blueprint: IBlueprint) {
84
- if (
85
- isNotEmpty<FactoryCommandHandler>(FactoryHandler) &&
86
- blueprint.is('stone.adapter.platform', NODE_CONSOLE_PLATFORM)
87
- ) {
88
- blueprint.set(defineCommand(FactoryHandler, { name: '*', isFactory: true }))
89
- }
90
- }
91
- })
92
-
93
78
  /**
94
79
  * Application options.
95
80
  */
@@ -14,22 +14,22 @@
14
14
  "build": "stone build",
15
15
  "preview": "stone preview",
16
16
  "typings": "stone typings",
17
- "test": "vitest run",
18
- "test:cvg": "npm run test -- --coverage"
17
+ "test": "stone test",
18
+ "test:cvg": "stone test --coverage"
19
19
  },
20
20
  "dependencies": {
21
21
  "react": "^19.0.0",
22
22
  "react-dom": "^19.0.0",
23
- "@stone-js/core": "^0.8.7",
24
- "@stone-js/use-react": "^0.8.7",
25
- "@stone-js/browser-adapter": "^0.8.7",
26
- "@stone-js/node-cli-adapter": "^0.8.7"
23
+ "@stone-js/core": "^0.8.9",
24
+ "@stone-js/use-react": "^0.8.9",
25
+ "@stone-js/browser-adapter": "^0.8.9"
27
26
  },
28
27
  "devDependencies": {
29
28
  "@babel/plugin-proposal-decorators": "^7.25.9",
30
29
  "@babel/preset-env": "^7.26.9",
31
30
  "@babel/preset-typescript": "^7.27.0",
32
- "@stone-js/cli": "^0.8.7",
31
+ "@stone-js/cli": "^0.8.9",
32
+ "@stone-js/testing": "^0.8.9",
33
33
  "@types/node": "^24.0.7",
34
34
  "@types/react": "^19.0.7",
35
35
  "@types/react-dom": "^19.0.3",
@@ -0,0 +1,16 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" width="96" height="96" role="img" aria-label="Stone.js">
2
+ <title>Stone.js</title>
3
+ <style>
4
+ .ink { stroke: #1B1613; }
5
+ @media (prefers-color-scheme: dark) { .ink { stroke: #EFE8DC; } }
6
+ </style>
7
+ <defs>
8
+ <linearGradient id="braise" gradientUnits="userSpaceOnUse" x1="22" y1="14" x2="74" y2="26.1">
9
+ <stop offset="0" stop-color="#FFC46B" />
10
+ <stop offset="1" stop-color="#FF5A1F" />
11
+ </linearGradient>
12
+ </defs>
13
+ <path class="ink" d="M 79.96 36.4 A 34 34 0 0 1 53.9 81.5" fill="none" stroke-width="11" stroke-linecap="round" opacity=".85" />
14
+ <path class="ink" d="M 42.1 81.5 A 34 34 0 0 1 16.05 36.4" fill="none" stroke-width="11" stroke-linecap="round" opacity=".85" />
15
+ <path d="M 22 26.1 A 34 34 0 0 1 74 26.1" fill="none" stroke="url(#braise)" stroke-width="11" stroke-linecap="round" />
16
+ </svg>
@@ -1,91 +1,30 @@
1
- import { renderToString } from 'react-dom/server'
2
- import { ILogger, IncomingEvent } from '@stone-js/core'
3
- import { FactoryHandler, AppConfig } from '../app/Application'
4
-
5
- vi.mock('@stone-js/core', async (mod) => {
6
- const actual: any = await mod()
7
- return {
8
- ...actual,
9
- isNotEmpty: vi.fn(() => true),
10
- defineConfig: (config: any) => config
11
- }
12
- })
13
-
14
- describe('Application', () => {
15
- let app: any
16
- let mockedLogger: ILogger
17
-
18
- beforeEach(() => {
19
- mockedLogger = {
20
- info: vi.fn(),
21
- } as unknown as ILogger
22
-
23
- app = FactoryHandler({ logger: mockedLogger })
24
- })
25
-
26
- it('should create an application instance', () => {
27
- // Assert
28
- expect(app).toBeInstanceOf(Object)
29
- })
30
-
31
- it('get head values', async () => {
32
- // Arrange
33
- const event = { get: () => 'World' } as unknown as IncomingEvent
34
-
35
- // Act
36
- const head = await app.head({ event })
37
-
38
- // Assert
39
- expect(head).toHaveProperty('metas')
40
- expect(head.title).toContain('Welcome to Stone.js')
41
- expect(head.title).toContain('World')
42
- expect(head).toHaveProperty('description')
1
+ import { createTestApp, makeIncomingHttpEvent } from '@stone-js/testing'
2
+
3
+ /**
4
+ * The whole application, booted in memory and asked a real question.
5
+ *
6
+ * Nothing is mocked and nothing is listed: `createTestApp()` discovers `app/**`, and the event goes
7
+ * through the same kernel production runs. If this passes the application works; if it fails the
8
+ * application is broken. That is the only kind of test worth shipping in a starter — the previous one
9
+ * stubbed out the framework's own decorators, which meant it could pass while nothing worked.
10
+ */
11
+ describe('Pages', () => {
12
+ it('renders the home page, data included', async () => {
13
+ const app = await createTestApp()
14
+
15
+ const response = await app.send(makeIncomingHttpEvent({ method: 'GET', url: '/?name=Ada' }))
16
+
17
+ expect(response.statusCode).toBe(200)
18
+ // A page is a handler, so a rendered page is a response whose body is HTML. Query that HTML with
19
+ // whatever you already use (happy-dom, jsdom, Testing Library): none is bundled here.
20
+ expect(response.html()).toContain('Ada')
43
21
  })
44
22
 
45
- it('should handle incoming events', () => {
46
- // Arrange
47
- const expectedMessage = 'Hello World!'
48
- const event = { get: () => 'World' } as unknown as IncomingEvent
23
+ it('renders without a name', async () => {
24
+ const app = await createTestApp()
49
25
 
50
- // Act
51
- const response = app.handle(event) as { message: string }
26
+ const response = await app.send(makeIncomingHttpEvent({ method: 'GET', url: '/' }))
52
27
 
53
- // Assert
54
- expect(response.message).toBe(expectedMessage)
55
- expect(mockedLogger.info).toHaveBeenCalledWith(expectedMessage)
28
+ expect(response.statusCode).toBe(200)
56
29
  })
57
-
58
- it('should render the message', () => {
59
- // Arrange
60
- const message = 'Hello World!'
61
-
62
- // Act
63
- const response = renderToString(app.render({ data: { message } } as any))
64
-
65
- // Assert
66
- expect(response).toContain(message)
67
- })
68
-
69
- it('should render the Stone.js logo', () => {
70
- // Act
71
- const response = renderToString(app.render({ data: { message: 'Hello World!' } } as any))
72
-
73
- // Assert
74
- expect(response).toContain('/logo.svg')
75
- expect(response).toContain('alt="Stone.js"')
76
- expect(response).toContain('Welcome to')
77
- expect(response).toContain('Stone.js')
78
- })
79
-
80
- it('should get config', () => {
81
- // Arrange
82
- const config: any = AppConfig
83
- const blueprint: any = { is: () => true, set: vi.fn() }
84
-
85
- // Act
86
- config.afterConfigure(blueprint)
87
-
88
- // Assert
89
- expect(blueprint.set).toHaveBeenCalled()
90
- })
91
- })
30
+ })
@@ -1,5 +1,4 @@
1
1
  import { NodeHttp } from '@stone-js/node-http-adapter'
2
- import { NodeConsole } from '@stone-js/node-cli-adapter'
3
2
  import { IncomingEvent, IEventHandler, ILogger, LogLevel, StoneApp } from '@stone-js/core'
4
3
 
5
4
  /**
@@ -10,7 +9,6 @@ import { IncomingEvent, IEventHandler, ILogger, LogLevel, StoneApp } from '@ston
10
9
  * @NodeHttp() is used to enable the Node HTTP adapter.
11
10
  * @StoneApp() is used to enable the Stone application, it is required.
12
11
  */
13
- @NodeConsole()
14
12
  @NodeHttp({ default: true })
15
13
  @StoneApp({ logger: { level: LogLevel.INFO } })
16
14
  export class Application implements IEventHandler<IncomingEvent> {
@@ -14,19 +14,19 @@
14
14
  "build": "stone build",
15
15
  "preview": "stone preview dist/server.mjs",
16
16
  "typings": "stone typings",
17
- "test": "vitest run",
18
- "test:cvg": "npm run test -- --coverage"
17
+ "test": "stone test",
18
+ "test:cvg": "stone test --coverage"
19
19
  },
20
20
  "dependencies": {
21
- "@stone-js/core": "^0.8.7",
22
- "@stone-js/node-cli-adapter": "^0.8.7",
23
- "@stone-js/node-http-adapter": "^0.8.7"
21
+ "@stone-js/core": "^0.8.9",
22
+ "@stone-js/node-http-adapter": "^0.8.9"
24
23
  },
25
24
  "devDependencies": {
26
25
  "@babel/plugin-proposal-decorators": "^7.25.9",
27
26
  "@babel/preset-env": "^7.26.9",
28
27
  "@babel/preset-typescript": "^7.27.0",
29
- "@stone-js/cli": "^0.8.7",
28
+ "@stone-js/cli": "^0.8.9",
29
+ "@stone-js/testing": "^0.8.9",
30
30
  "@types/node": "^24.0.7",
31
31
  "@vitest/coverage-v8": "^3.0.9",
32
32
  "vitest": "^3.0.9"
@@ -1,61 +1,28 @@
1
- import { Application } from '../app/Application'
2
- import { ILogger, IncomingEvent } from '@stone-js/core'
3
-
4
- // We must mock decorators to lighten the test environment
5
- vi.mock(import("@stone-js/core"), async (importOriginal) => {
6
- const actual = await importOriginal()
7
- return {
8
- ...actual,
9
- StoneApp: vi.fn(() => vi.fn()),
10
- }
11
- })
12
-
13
- // We must mock decorators to lighten the test environment
14
- vi.mock(import("@stone-js/node-cli-adapter"), async (importOriginal) => {
15
- const actual = await importOriginal()
16
- return {
17
- ...actual,
18
- NodeConsole: vi.fn(() => vi.fn()),
19
- }
20
- })
21
-
22
- // We must mock decorators to lighten the test environment
23
- vi.mock(import("@stone-js/node-http-adapter"), async (importOriginal) => {
24
- const actual = await importOriginal()
25
- return {
26
- ...actual,
27
- NodeHttp: vi.fn(() => vi.fn()),
28
- }
29
- })
30
-
1
+ import { createTestApp, makeIncomingHttpEvent } from '@stone-js/testing'
2
+
3
+ /**
4
+ * The whole application, booted in memory and asked a real question.
5
+ *
6
+ * Nothing is mocked and nothing is listed: `createTestApp()` discovers `app/**`, and the event goes
7
+ * through the same kernel production runs. If this passes the application works; if it fails the
8
+ * application is broken. That is the only kind of test worth shipping in a starter — the previous one
9
+ * stubbed out the framework's own decorators, which meant it could pass while nothing worked.
10
+ */
31
11
  describe('Application', () => {
32
- let app: Application
33
- let mockedLogger: ILogger
12
+ it('answers the caller', async () => {
13
+ const app = await createTestApp()
34
14
 
35
- beforeEach(() => {
36
- mockedLogger = {
37
- info: vi.fn(),
38
- } as unknown as ILogger
15
+ const response = await app.send(makeIncomingHttpEvent({ method: 'GET', url: '/?name=Ada' }))
39
16
 
40
- app = new Application({ logger: mockedLogger })
17
+ expect(response.statusCode).toBe(200)
18
+ expect(response.json()).toMatchObject({ message: expect.stringContaining('Ada') })
41
19
  })
42
20
 
43
- it('should create an application instance', () => {
44
- // Assert
45
- expect(app).toBeInstanceOf(Application)
46
- })
21
+ it('answers when nobody says who they are', async () => {
22
+ const app = await createTestApp()
47
23
 
48
- it('should handle incoming events', () => {
49
- // Arrange
50
- const expectedMessage = 'Hello World! Welcome to Stone.js.'
51
- const event = { get: () => 'World' } as unknown as IncomingEvent
24
+ const response = await app.send(makeIncomingHttpEvent({ method: 'GET', url: '/' }))
52
25
 
53
- // Act
54
- const response = app.handle(event)
55
-
56
- // Assert
57
- expect(response.message).toBe(expectedMessage)
58
- expect(response.framework.name).toBe('Stone.js')
59
- expect(mockedLogger.info).toHaveBeenCalledWith(expectedMessage)
26
+ expect(response.statusCode).toBe(200)
60
27
  })
61
- })
28
+ })
@@ -1,6 +1,5 @@
1
1
  import { NODE_HTTP_PLATFORM, nodeHttpAdapterBlueprint } from '@stone-js/node-http-adapter'
2
- import { defineCommand, NODE_CONSOLE_PLATFORM, nodeConsoleAdapterBlueprint } from '@stone-js/node-cli-adapter'
3
- import { defineStoneApp, defineConfig, IBlueprint, ILogger, IncomingEvent, FunctionalEventHandler } from '@stone-js/core'
2
+ import { defineStoneApp, ILogger, IncomingEvent, FunctionalEventHandler } from '@stone-js/core'
4
3
 
5
4
  /**
6
5
  * Create an handler using the factory handler.
@@ -40,20 +39,9 @@ export const Application = defineStoneApp(
40
39
  isFactory: true,
41
40
  adapter: { platform: NODE_HTTP_PLATFORM }
42
41
  },
43
- [nodeHttpAdapterBlueprint, nodeConsoleAdapterBlueprint]
42
+ [nodeHttpAdapterBlueprint]
44
43
  )
45
44
 
46
- /**
47
- * Application configuration.
48
- */
49
- export const AppConfig = defineConfig({
50
- afterConfigure (blueprint: IBlueprint) {
51
- if (blueprint.is('stone.adapter.platform', NODE_CONSOLE_PLATFORM)) {
52
- blueprint.set(defineCommand(FactoryHandler, { name: '*', isFactory: true }))
53
- }
54
- }
55
- })
56
-
57
45
  /**
58
46
  * Application options.
59
47
  */
@@ -14,19 +14,19 @@
14
14
  "build": "stone build",
15
15
  "preview": "stone preview dist/server.mjs",
16
16
  "typings": "stone typings",
17
- "test": "vitest run",
18
- "test:cvg": "npm run test -- --coverage"
17
+ "test": "stone test",
18
+ "test:cvg": "stone test --coverage"
19
19
  },
20
20
  "dependencies": {
21
- "@stone-js/core": "^0.8.7",
22
- "@stone-js/node-cli-adapter": "^0.8.7",
23
- "@stone-js/node-http-adapter": "^0.8.7"
21
+ "@stone-js/core": "^0.8.9",
22
+ "@stone-js/node-http-adapter": "^0.8.9"
24
23
  },
25
24
  "devDependencies": {
26
25
  "@babel/plugin-proposal-decorators": "^7.25.9",
27
26
  "@babel/preset-env": "^7.26.9",
28
27
  "@babel/preset-typescript": "^7.27.0",
29
- "@stone-js/cli": "^0.8.7",
28
+ "@stone-js/cli": "^0.8.9",
29
+ "@stone-js/testing": "^0.8.9",
30
30
  "@types/node": "^24.0.7",
31
31
  "@vitest/coverage-v8": "^3.0.9",
32
32
  "vitest": "^3.0.9"