@gravito/signal 1.0.0-alpha.6 → 1.0.0

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,61 @@
1
+ import { describe, expect, it, mock } from 'bun:test'
2
+ import { DevMailbox } from '../src/dev/DevMailbox'
3
+ import { Mailable } from '../src/Mailable'
4
+ import { OrbitSignal } from '../src/OrbitSignal'
5
+ import { MemoryTransport } from '../src/transports/MemoryTransport'
6
+
7
+ class DemoMail extends Mailable {
8
+ build() {
9
+ return this.from('from@example.com')
10
+ .to('to@example.com')
11
+ .cc('cc@example.com')
12
+ .bcc('bcc@example.com')
13
+ .replyTo('reply@example.com')
14
+ .subject('Hello')
15
+ .emailPriority('high')
16
+ .html('<p>Hello World</p>')
17
+ }
18
+ }
19
+
20
+ describe('Mailable', () => {
21
+ it('builds envelopes and renders content', async () => {
22
+ const mail = new DemoMail()
23
+ const envelope = await mail.buildEnvelope({
24
+ from: { address: 'default@example.com' },
25
+ translator: (key: string) => `t:${key}`,
26
+ })
27
+
28
+ expect(envelope.from?.address).toBe('from@example.com')
29
+ expect(envelope.cc?.[0]?.address).toBe('cc@example.com')
30
+ expect(envelope.bcc?.[0]?.address).toBe('bcc@example.com')
31
+ expect(envelope.replyTo?.address).toBe('reply@example.com')
32
+
33
+ const content = await mail.renderContent()
34
+ expect(content.html).toContain('<p>Hello World</p>')
35
+ expect(content.text).toBe('Hello World')
36
+ expect(mail.t('hello')).toBe('t:hello')
37
+ })
38
+
39
+ it('queues mailables via OrbitSignal', async () => {
40
+ const queueMock = mock(async () => {})
41
+ const orbit = new OrbitSignal({
42
+ transport: new MemoryTransport(new DevMailbox()),
43
+ })
44
+
45
+ // 模擬容器中的隊列服務
46
+ ;(orbit as any).core = {
47
+ container: {
48
+ make: (key: string) => {
49
+ if (key === 'queue') {
50
+ return { push: queueMock }
51
+ }
52
+ return null
53
+ },
54
+ },
55
+ }
56
+
57
+ const mail = new DemoMail()
58
+ await orbit.queue(mail)
59
+ expect(queueMock).toHaveBeenCalled()
60
+ })
61
+ })
@@ -27,7 +27,7 @@ describe('OrbitSignal Core', () => {
27
27
  it('should send a simple email via transport', async () => {
28
28
  const transport = new MockTransport()
29
29
 
30
- const mailer = OrbitSignal.configure({
30
+ const mailer = new OrbitSignal({
31
31
  from: { name: 'System', address: 'system@example.com' },
32
32
  transport: transport,
33
33
  })
@@ -49,7 +49,7 @@ describe('OrbitSignal Core', () => {
49
49
  const mail = new WelcomeMail('Carl')
50
50
  .to(['a@b.com', { address: 'c@d.com', name: 'C' }])
51
51
  .cc('cc@example.com')
52
- .priority('high')
52
+ .emailPriority('high')
53
53
 
54
54
  const config = {
55
55
  from: { address: 'default@example.com' },
@@ -0,0 +1,43 @@
1
+ import { describe, expect, it } from 'bun:test'
2
+ import { DevMailbox } from '../src/dev/DevMailbox'
3
+ import { Mailable } from '../src/Mailable'
4
+ import { OrbitSignal } from '../src/OrbitSignal'
5
+ import { MemoryTransport } from '../src/transports/MemoryTransport'
6
+
7
+ class EmptyMail extends Mailable {
8
+ build() {
9
+ return this.html('<p>Hi</p>')
10
+ }
11
+ }
12
+
13
+ describe('OrbitSignal', () => {
14
+ it('sends messages via transport and validates fields', async () => {
15
+ const mailboxTransport = new MemoryTransport(new DevMailbox())
16
+ const orbit = new OrbitSignal({ transport: mailboxTransport })
17
+
18
+ // No from address
19
+ await expect(orbit.send(new EmptyMail())).rejects.toThrow('Message is missing "from"')
20
+
21
+ class ValidMail extends Mailable {
22
+ build() {
23
+ return this.from('from@example.com').to('to@example.com').html('<p>Hi</p>')
24
+ }
25
+ }
26
+
27
+ await expect(orbit.send(new ValidMail())).resolves.toBeUndefined()
28
+ })
29
+
30
+ it('queues immediately when no queue service is present', async () => {
31
+ const transport = new MemoryTransport(new DevMailbox())
32
+ const orbit = new OrbitSignal({ transport })
33
+
34
+ class ValidMail extends Mailable {
35
+ build() {
36
+ return this.from('from@example.com').to('to@example.com').html('<p>Hi</p>')
37
+ }
38
+ }
39
+
40
+ // Should resolve without crashing (internally falls back to send)
41
+ await expect(orbit.queue(new ValidMail())).resolves.toBeUndefined()
42
+ })
43
+ })
@@ -1,6 +1,4 @@
1
1
  import { describe, expect, it } from 'bun:test'
2
- import { createElement } from 'react'
3
- import { defineComponent, h } from 'vue'
4
2
  import { Mailable } from '../src/Mailable'
5
3
  import { LogTransport } from '../src/transports/LogTransport'
6
4
 
@@ -11,27 +9,31 @@ const mockConfig = {
11
9
  }
12
10
 
13
11
  // React Component
14
- const ReactTestComponent = ({ name }: { name: string }) => {
15
- return createElement('div', {}, createElement('h1', {}, `Hello ${name}`))
12
+ const ReactTestComponent = ({ name }: { name: string }) => `<h1>Hello ${name}</h1>`
13
+
14
+ const reactDeps = {
15
+ createElement: (component: (props: any) => string, props: any) => component(props),
16
+ renderToStaticMarkup: (element: string) => element,
16
17
  }
17
18
 
18
19
  // Vue Component
19
- const VueTestComponent = defineComponent({
20
- props: ['name'],
21
- render() {
22
- return h('div', [h('h1', `Hello ${this.name}`)])
23
- },
24
- })
20
+ const VueTestComponent = ({ name }: { name: string }) => `<h1>Hello ${name}</h1>`
21
+
22
+ const vueDeps = {
23
+ createSSRApp: ({ render }: { render: () => string }) => ({ render }),
24
+ h: (component: (props: any) => string, props: any) => component(props),
25
+ renderToString: async (app: { render: () => string }) => app.render(),
26
+ }
25
27
 
26
28
  class TestReactMail extends Mailable {
27
29
  build() {
28
- return this.react(ReactTestComponent, { name: 'World' }).subject('React Test')
30
+ return this.react(ReactTestComponent, { name: 'World' }, reactDeps).subject('React Test')
29
31
  }
30
32
  }
31
33
 
32
34
  class TestVueMail extends Mailable {
33
35
  build() {
34
- return this.vue(VueTestComponent, { name: 'World' }).subject('Vue Test')
36
+ return this.vue(VueTestComponent, { name: 'World' }, vueDeps).subject('Vue Test')
35
37
  }
36
38
  }
37
39
 
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it, mock } from 'bun:test'
2
+
3
+ mock.module('@gravito/prism', () => ({
4
+ TemplateEngine: class {
5
+ constructor(private dir: string) {
6
+ this.dir = dir
7
+ }
8
+ render(template: string) {
9
+ return `<div>${this.dir}:${template}</div>`
10
+ }
11
+ },
12
+ }))
13
+
14
+ const { TemplateRenderer } = await import('../src/renderers/TemplateRenderer')
15
+
16
+ describe('TemplateRenderer', () => {
17
+ it('renders templates and strips html', async () => {
18
+ const renderer = new TemplateRenderer('welcome', '/views')
19
+ const result = await renderer.render({ name: 'Ada' })
20
+
21
+ expect(result.html).toContain('/views:welcome')
22
+ expect(result.text).toBe('/views:welcome')
23
+ })
24
+ })
@@ -0,0 +1,37 @@
1
+ import { describe, expect, it } from 'bun:test'
2
+ import { getMailboxHtml } from '../src/dev/ui/mailbox'
3
+ import { getPreviewHtml } from '../src/dev/ui/preview'
4
+ import { layout } from '../src/dev/ui/shared'
5
+
6
+ describe('Dev UI', () => {
7
+ it('renders mailbox and preview HTML', () => {
8
+ const entry = {
9
+ id: '1',
10
+ envelope: {
11
+ from: { address: 'from@example.com' },
12
+ to: [{ address: 'to@example.com' }],
13
+ subject: 'Hello',
14
+ priority: 'high',
15
+ },
16
+ html: '<p>Hi</p>',
17
+ text: 'Hi',
18
+ sentAt: new Date('2024-01-01T00:00:00Z'),
19
+ }
20
+
21
+ const mailbox = getMailboxHtml([entry], '/__mail')
22
+ expect(mailbox).toContain('Gravito Mailbox')
23
+ expect(mailbox).toContain('badge-high')
24
+
25
+ const preview = getPreviewHtml(entry, '/__mail')
26
+ expect(preview).toContain('Email Preview')
27
+ expect(preview).toContain('Hello')
28
+
29
+ const wrapped = layout('Title', '<div>Content</div>')
30
+ expect(wrapped).toContain('<title>Title')
31
+ })
32
+
33
+ it('renders empty mailbox state', () => {
34
+ const html = getMailboxHtml([], '/__mail')
35
+ expect(html).toContain('No emails found')
36
+ })
37
+ })
package/tsconfig.json CHANGED
@@ -4,9 +4,16 @@
4
4
  "outDir": "./dist",
5
5
  "baseUrl": ".",
6
6
  "paths": {
7
- "gravito-core": ["../../packages/core/src/index.ts"],
8
- "@gravito/*": ["../../packages/*/src/index.ts"]
9
- }
7
+ "@gravito/core": [
8
+ "../../packages/core/src/index.ts"
9
+ ],
10
+ "@gravito/*": [
11
+ "../../packages/*/src/index.ts"
12
+ ]
13
+ },
14
+ "types": [
15
+ "bun-types"
16
+ ]
10
17
  },
11
18
  "include": [
12
19
  "src/**/*"
@@ -16,4 +23,4 @@
16
23
  "dist",
17
24
  "**/*.test.ts"
18
25
  ]
19
- }
26
+ }