Skip to content

Commit 4961580

Browse files
✅ test: add tests for INTERNAL_APP_URL feature
Add comprehensive test coverage for INTERNAL_APP_URL: - Test fallback behavior to APP_URL when INTERNAL_APP_URL is not set - Test explicit INTERNAL_APP_URL configuration - Test localhost bypass for CDN/proxy - Test createAsyncServerClient using INTERNAL_APP_URL - Test authentication headers in async calls Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
1 parent 95734e8 commit 4961580

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

src/envs/__tests__/app.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,39 @@ describe('getServerConfig', () => {
5353
);
5454
});
5555
});
56+
57+
describe('INTERNAL_APP_URL', () => {
58+
it('should default to APP_URL when INTERNAL_APP_URL is not set', () => {
59+
process.env.APP_URL = 'https://example.com';
60+
delete process.env.INTERNAL_APP_URL;
61+
62+
const config = getAppConfig();
63+
expect(config.INTERNAL_APP_URL).toBe('https://example.com');
64+
});
65+
66+
it('should use INTERNAL_APP_URL when explicitly set', () => {
67+
process.env.APP_URL = 'https://public.example.com';
68+
process.env.INTERNAL_APP_URL = 'http://localhost:3210';
69+
70+
const config = getAppConfig();
71+
expect(config.INTERNAL_APP_URL).toBe('http://localhost:3210');
72+
});
73+
74+
it('should use INTERNAL_APP_URL over APP_URL when both are set', () => {
75+
process.env.APP_URL = 'https://public.example.com';
76+
process.env.INTERNAL_APP_URL = 'http://internal-service:3210';
77+
78+
const config = getAppConfig();
79+
expect(config.APP_URL).toBe('https://public.example.com');
80+
expect(config.INTERNAL_APP_URL).toBe('http://internal-service:3210');
81+
});
82+
83+
it('should handle localhost INTERNAL_APP_URL for bypassing CDN', () => {
84+
process.env.APP_URL = 'https://cloudflare-proxied.com';
85+
process.env.INTERNAL_APP_URL = 'http://127.0.0.1:3210';
86+
87+
const config = getAppConfig();
88+
expect(config.INTERNAL_APP_URL).toBe('http://127.0.0.1:3210');
89+
});
90+
});
5691
});
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// @vitest-environment node
2+
import { describe, expect, it, vi } from 'vitest';
3+
4+
import { appEnv } from '@/envs/app';
5+
6+
// Mock the dependencies
7+
vi.mock('@/envs/app', () => ({
8+
appEnv: {
9+
APP_URL: 'https://public.example.com',
10+
INTERNAL_APP_URL: 'http://localhost:3210',
11+
},
12+
}));
13+
14+
vi.mock('@/config/db', () => ({
15+
serverDBEnv: {
16+
KEY_VAULTS_SECRET: 'test-secret',
17+
},
18+
}));
19+
20+
vi.mock('@/server/modules/KeyVaultsEncrypt', () => ({
21+
KeyVaultsGateKeeper: {
22+
initWithEnvKey: vi.fn().mockResolvedValue({
23+
encrypt: vi.fn().mockResolvedValue('encrypted-data'),
24+
}),
25+
},
26+
}));
27+
28+
vi.mock('@trpc/client', () => ({
29+
createTRPCClient: vi.fn((config: any) => {
30+
// Store the config for inspection
31+
return {
32+
_config: config,
33+
};
34+
}),
35+
httpLink: vi.fn((options: any) => options),
36+
}));
37+
38+
describe('createAsyncServerClient', () => {
39+
it('should use INTERNAL_APP_URL for server-to-server calls', async () => {
40+
const { createAsyncServerClient } = await import('../caller');
41+
const { createTRPCClient } = await import('@trpc/client');
42+
43+
await createAsyncServerClient('test-user-id', { test: 'payload' });
44+
45+
expect(createTRPCClient).toHaveBeenCalled();
46+
const callArgs = vi.mocked(createTRPCClient).mock.calls[0][0];
47+
const httpLinkConfig = callArgs.links[0];
48+
49+
// Verify that the URL uses INTERNAL_APP_URL
50+
expect(httpLinkConfig.url).toContain('localhost:3210');
51+
expect(httpLinkConfig.url).toBe('http://localhost:3210/trpc/async');
52+
});
53+
54+
it('should fall back to APP_URL when INTERNAL_APP_URL is not set', async () => {
55+
// Mock appEnv without INTERNAL_APP_URL
56+
vi.mocked(appEnv).INTERNAL_APP_URL = undefined;
57+
vi.mocked(appEnv).APP_URL = 'https://fallback.example.com';
58+
59+
const { createAsyncServerClient } = await import('../caller');
60+
const { createTRPCClient } = await import('@trpc/client');
61+
62+
// Clear previous mocks
63+
vi.clearAllMocks();
64+
65+
await createAsyncServerClient('test-user-id', { test: 'payload' });
66+
67+
expect(createTRPCClient).toHaveBeenCalled();
68+
const callArgs = vi.mocked(createTRPCClient).mock.calls[0][0];
69+
const httpLinkConfig = callArgs.links[0];
70+
71+
// Verify that the URL falls back to APP_URL
72+
expect(httpLinkConfig.url).toBe('https://fallback.example.com/trpc/async');
73+
});
74+
75+
it('should bypass CDN when INTERNAL_APP_URL points to localhost', async () => {
76+
vi.mocked(appEnv).APP_URL = 'https://cloudflare-proxied.com';
77+
vi.mocked(appEnv).INTERNAL_APP_URL = 'http://127.0.0.1:3210';
78+
79+
const { createAsyncServerClient } = await import('../caller');
80+
const { createTRPCClient } = await import('@trpc/client');
81+
82+
// Clear previous mocks
83+
vi.clearAllMocks();
84+
85+
await createAsyncServerClient('test-user-id', { test: 'payload' });
86+
87+
expect(createTRPCClient).toHaveBeenCalled();
88+
const callArgs = vi.mocked(createTRPCClient).mock.calls[0][0];
89+
const httpLinkConfig = callArgs.links[0];
90+
91+
// Verify that localhost is used to bypass CDN
92+
expect(httpLinkConfig.url).toBe('http://127.0.0.1:3210/trpc/async');
93+
expect(httpLinkConfig.url).not.toContain('cloudflare-proxied');
94+
});
95+
96+
it('should include proper authentication headers', async () => {
97+
vi.mocked(appEnv).INTERNAL_APP_URL = 'http://localhost:3210';
98+
99+
const { createAsyncServerClient } = await import('../caller');
100+
const { KeyVaultsGateKeeper } = await import('@/server/modules/KeyVaultsEncrypt');
101+
const { serverDBEnv } = await import('@/config/db');
102+
103+
// Clear previous mocks
104+
vi.clearAllMocks();
105+
106+
const mockGateKeeper = {
107+
encrypt: vi.fn().mockResolvedValue('encrypted-test-data'),
108+
};
109+
vi.mocked(KeyVaultsGateKeeper.initWithEnvKey).mockResolvedValue(mockGateKeeper as any);
110+
111+
await createAsyncServerClient('user-123', { clientSecret: 'test-secret' });
112+
113+
// Verify encryption was called with correct data
114+
expect(mockGateKeeper.encrypt).toHaveBeenCalledWith(
115+
JSON.stringify({ payload: { clientSecret: 'test-secret' }, userId: 'user-123' }),
116+
);
117+
118+
// Verify KeyVaultsGateKeeper was initialized
119+
expect(KeyVaultsGateKeeper.initWithEnvKey).toHaveBeenCalled();
120+
});
121+
});

0 commit comments

Comments
 (0)