ci: Update AppService tests to initialize app config instead of app.locals

This commit is contained in:
Danny Avila 2025-08-17 17:18:52 -04:00
parent 3ecb96149a
commit 5b43bf6c95
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956

View file

@ -54,6 +54,11 @@ jest.mock('./Config', () => ({
}, },
}), }),
})); }));
jest.mock('./Config/getAppConfig', () => ({
initializeAppConfig: jest.fn(),
getAppConfig: jest.fn(),
}));
jest.mock('./ToolService', () => ({ jest.mock('./ToolService', () => ({
loadAndFormatTools: jest.fn().mockReturnValue({ loadAndFormatTools: jest.fn().mockReturnValue({
ExampleTool: { ExampleTool: {
@ -117,23 +122,23 @@ const azureGroups = [
]; ];
describe('AppService', () => { describe('AppService', () => {
let app;
const mockedTurnstileConfig = { const mockedTurnstileConfig = {
siteKey: 'default-site-key', siteKey: 'default-site-key',
options: {}, options: {},
}; };
const { initializeAppConfig } = require('./Config/getAppConfig');
beforeEach(() => { beforeEach(() => {
app = { locals: {} };
process.env.CDN_PROVIDER = undefined; process.env.CDN_PROVIDER = undefined;
jest.clearAllMocks();
}); });
it('should correctly assign process.env and app.locals based on custom config', async () => { it('should correctly assign process.env and initialize app config based on custom config', async () => {
await AppService(app); await AppService();
expect(process.env.CDN_PROVIDER).toEqual('testStrategy'); expect(process.env.CDN_PROVIDER).toEqual('testStrategy');
expect(app.locals).toEqual({ expect(initializeAppConfig).toHaveBeenCalledWith({
config: expect.objectContaining({ config: expect.objectContaining({
fileStrategy: 'testStrategy', fileStrategy: 'testStrategy',
}), }),
@ -187,7 +192,7 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
const { logger } = require('~/config'); const { logger } = require('~/config');
expect(logger.info).toHaveBeenCalledWith(expect.stringContaining('Outdated Config version')); expect(logger.info).toHaveBeenCalledWith(expect.stringContaining('Outdated Config version'));
@ -201,8 +206,12 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(app.locals.imageOutputType).toEqual(EImageOutputType.WEBP); expect(initializeAppConfig).toHaveBeenCalledWith(
expect.objectContaining({
imageOutputType: EImageOutputType.WEBP,
}),
);
}); });
it('should default to `PNG` `imageOutputType` with no provided type', async () => { it('should default to `PNG` `imageOutputType` with no provided type', async () => {
@ -212,15 +221,23 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(app.locals.imageOutputType).toEqual(EImageOutputType.PNG); expect(initializeAppConfig).toHaveBeenCalledWith(
expect.objectContaining({
imageOutputType: EImageOutputType.PNG,
}),
);
}); });
it('should default to `PNG` `imageOutputType` with no provided config', async () => { it('should default to `PNG` `imageOutputType` with no provided config', async () => {
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(undefined)); require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(undefined));
await AppService(app); await AppService();
expect(app.locals.imageOutputType).toEqual(EImageOutputType.PNG); expect(initializeAppConfig).toHaveBeenCalledWith(
expect.objectContaining({
imageOutputType: EImageOutputType.PNG,
}),
);
}); });
it('should initialize Firebase when fileStrategy is firebase', async () => { it('should initialize Firebase when fileStrategy is firebase', async () => {
@ -230,7 +247,7 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
const { initializeFirebase } = require('./Files/Firebase/initialize'); const { initializeFirebase } = require('./Files/Firebase/initialize');
expect(initializeFirebase).toHaveBeenCalled(); expect(initializeFirebase).toHaveBeenCalled();
@ -242,7 +259,7 @@ describe('AppService', () => {
const { loadAndFormatTools } = require('./ToolService'); const { loadAndFormatTools } = require('./ToolService');
const { setCachedTools, getCachedTools } = require('./Config'); const { setCachedTools, getCachedTools } = require('./Config');
await AppService(app); await AppService();
expect(loadAndFormatTools).toHaveBeenCalledWith({ expect(loadAndFormatTools).toHaveBeenCalledWith({
adminFilter: undefined, adminFilter: undefined,
@ -305,17 +322,18 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(app.locals).toHaveProperty(EModelEndpoint.assistants); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals[EModelEndpoint.assistants]).toEqual(
expect.objectContaining({ expect.objectContaining({
[EModelEndpoint.assistants]: expect.objectContaining({
disableBuilder: true, disableBuilder: true,
pollIntervalMs: 5000, pollIntervalMs: 5000,
timeoutMs: 30000, timeoutMs: 30000,
supportedIds: expect.arrayContaining(['id1', 'id2']), supportedIds: expect.arrayContaining(['id1', 'id2']),
privateAssistants: false, privateAssistants: false,
}), }),
}),
); );
}); });
@ -334,16 +352,20 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(app.locals).toHaveProperty(EModelEndpoint.agents); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals[EModelEndpoint.agents]).toEqual(
expect.objectContaining({ expect.objectContaining({
[EModelEndpoint.agents]: expect.objectContaining({
disableBuilder: true, disableBuilder: true,
recursionLimit: 10, recursionLimit: 10,
maxRecursionLimit: 20, maxRecursionLimit: 20,
allowedProviders: expect.arrayContaining(['openai', 'anthropic']), allowedProviders: expect.arrayContaining(['openai', 'anthropic']),
capabilities: expect.arrayContaining([AgentCapabilities.tools, AgentCapabilities.actions]), capabilities: expect.arrayContaining([
AgentCapabilities.tools,
AgentCapabilities.actions,
]),
}),
}), }),
); );
}); });
@ -351,14 +373,15 @@ describe('AppService', () => {
it('should configure Agents endpoint with defaults when no config is provided', async () => { it('should configure Agents endpoint with defaults when no config is provided', async () => {
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve({})); require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve({}));
await AppService(app); await AppService();
expect(app.locals).toHaveProperty(EModelEndpoint.agents); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals[EModelEndpoint.agents]).toEqual(
expect.objectContaining({ expect.objectContaining({
[EModelEndpoint.agents]: expect.objectContaining({
disableBuilder: false, disableBuilder: false,
capabilities: expect.arrayContaining([...defaultAgentCapabilities]), capabilities: expect.arrayContaining([...defaultAgentCapabilities]),
}), }),
}),
); );
}); });
@ -373,14 +396,18 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(app.locals).toHaveProperty(EModelEndpoint.agents); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals[EModelEndpoint.agents]).toEqual(
expect.objectContaining({ expect.objectContaining({
[EModelEndpoint.agents]: expect.objectContaining({
disableBuilder: false, disableBuilder: false,
capabilities: expect.arrayContaining([...defaultAgentCapabilities]), capabilities: expect.arrayContaining([...defaultAgentCapabilities]),
}), }),
[EModelEndpoint.openAI]: expect.objectContaining({
titleConvo: true,
}),
}),
); );
}); });
@ -400,9 +427,18 @@ describe('AppService', () => {
process.env.WESTUS_API_KEY = 'westus-key'; process.env.WESTUS_API_KEY = 'westus-key';
process.env.EASTUS_API_KEY = 'eastus-key'; process.env.EASTUS_API_KEY = 'eastus-key';
await AppService(app); await AppService();
expect(app.locals).toHaveProperty(EModelEndpoint.azureAssistants); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals[EModelEndpoint.azureAssistants].capabilities.length).toEqual(3); expect.objectContaining({
[EModelEndpoint.azureAssistants]: expect.objectContaining({
capabilities: expect.arrayContaining([
expect.any(String),
expect.any(String),
expect.any(String),
]),
}),
}),
);
}); });
it('should correctly configure Azure OpenAI endpoint based on custom config', async () => { it('should correctly configure Azure OpenAI endpoint based on custom config', async () => {
@ -419,18 +455,18 @@ describe('AppService', () => {
process.env.WESTUS_API_KEY = 'westus-key'; process.env.WESTUS_API_KEY = 'westus-key';
process.env.EASTUS_API_KEY = 'eastus-key'; process.env.EASTUS_API_KEY = 'eastus-key';
await AppService(app); await AppService();
expect(app.locals).toHaveProperty(EModelEndpoint.azureOpenAI);
const azureConfig = app.locals[EModelEndpoint.azureOpenAI];
expect(azureConfig).toHaveProperty('modelNames');
expect(azureConfig).toHaveProperty('modelGroupMap');
expect(azureConfig).toHaveProperty('groupMap');
const { modelNames, modelGroupMap, groupMap } = validateAzureGroups(azureGroups); const { modelNames, modelGroupMap, groupMap } = validateAzureGroups(azureGroups);
expect(azureConfig.modelNames).toEqual(modelNames); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(azureConfig.modelGroupMap).toEqual(modelGroupMap); expect.objectContaining({
expect(azureConfig.groupMap).toEqual(groupMap); [EModelEndpoint.azureOpenAI]: expect.objectContaining({
modelNames,
modelGroupMap,
groupMap,
}),
}),
);
}); });
it('should not modify FILE_UPLOAD environment variables without rate limits', async () => { it('should not modify FILE_UPLOAD environment variables without rate limits', async () => {
@ -442,7 +478,7 @@ describe('AppService', () => {
const initialEnv = { ...process.env }; const initialEnv = { ...process.env };
await AppService(app); await AppService();
// Expect environment variables to remain unchanged // Expect environment variables to remain unchanged
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual(initialEnv.FILE_UPLOAD_IP_MAX); expect(process.env.FILE_UPLOAD_IP_MAX).toEqual(initialEnv.FILE_UPLOAD_IP_MAX);
@ -468,7 +504,7 @@ describe('AppService', () => {
Promise.resolve(rateLimitsConfig), Promise.resolve(rateLimitsConfig),
); );
await AppService(app); await AppService();
// Verify that process.env has been updated according to the rate limits config // Verify that process.env has been updated according to the rate limits config
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual('100'); expect(process.env.FILE_UPLOAD_IP_MAX).toEqual('100');
@ -484,7 +520,7 @@ describe('AppService', () => {
process.env.FILE_UPLOAD_USER_MAX = 'initialUserMax'; process.env.FILE_UPLOAD_USER_MAX = 'initialUserMax';
process.env.FILE_UPLOAD_USER_WINDOW = 'initialUserWindow'; process.env.FILE_UPLOAD_USER_WINDOW = 'initialUserWindow';
await AppService(app); await AppService();
// Verify that process.env falls back to the initial values // Verify that process.env falls back to the initial values
expect(process.env.FILE_UPLOAD_IP_MAX).toEqual('initialMax'); expect(process.env.FILE_UPLOAD_IP_MAX).toEqual('initialMax');
@ -502,7 +538,7 @@ describe('AppService', () => {
const initialEnv = { ...process.env }; const initialEnv = { ...process.env };
await AppService(app); await AppService();
// Expect environment variables to remain unchanged // Expect environment variables to remain unchanged
expect(process.env.IMPORT_IP_MAX).toEqual(initialEnv.IMPORT_IP_MAX); expect(process.env.IMPORT_IP_MAX).toEqual(initialEnv.IMPORT_IP_MAX);
@ -528,7 +564,7 @@ describe('AppService', () => {
Promise.resolve(importLimitsConfig), Promise.resolve(importLimitsConfig),
); );
await AppService(app); await AppService();
// Verify that process.env has been updated according to the rate limits config // Verify that process.env has been updated according to the rate limits config
expect(process.env.IMPORT_IP_MAX).toEqual('150'); expect(process.env.IMPORT_IP_MAX).toEqual('150');
@ -544,7 +580,7 @@ describe('AppService', () => {
process.env.IMPORT_USER_MAX = 'initialUserMax'; process.env.IMPORT_USER_MAX = 'initialUserMax';
process.env.IMPORT_USER_WINDOW = 'initialUserWindow'; process.env.IMPORT_USER_WINDOW = 'initialUserWindow';
await AppService(app); await AppService();
// Verify that process.env falls back to the initial values // Verify that process.env falls back to the initial values
expect(process.env.IMPORT_IP_MAX).toEqual('initialMax'); expect(process.env.IMPORT_IP_MAX).toEqual('initialMax');
@ -581,38 +617,33 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
// Check OpenAI endpoint configuration expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals).toHaveProperty(EModelEndpoint.openAI);
expect(app.locals[EModelEndpoint.openAI]).toEqual(
expect.objectContaining({ expect.objectContaining({
// Check OpenAI endpoint configuration
[EModelEndpoint.openAI]: expect.objectContaining({
titleConvo: true, titleConvo: true,
titleModel: 'gpt-3.5-turbo', titleModel: 'gpt-3.5-turbo',
titleMethod: 'structured', titleMethod: 'structured',
titlePrompt: 'Custom title prompt for conversation', titlePrompt: 'Custom title prompt for conversation',
titlePromptTemplate: 'Summarize this conversation: {{conversation}}', titlePromptTemplate: 'Summarize this conversation: {{conversation}}',
}), }),
);
// Check Assistants endpoint configuration // Check Assistants endpoint configuration
expect(app.locals).toHaveProperty(EModelEndpoint.assistants); [EModelEndpoint.assistants]: expect.objectContaining({
expect(app.locals[EModelEndpoint.assistants]).toMatchObject({
titleMethod: 'functions', titleMethod: 'functions',
titlePrompt: 'Generate a title for this assistant conversation', titlePrompt: 'Generate a title for this assistant conversation',
titlePromptTemplate: 'Assistant conversation template: {{messages}}', titlePromptTemplate: 'Assistant conversation template: {{messages}}',
}); }),
// Check Azure OpenAI endpoint configuration // Check Azure OpenAI endpoint configuration
expect(app.locals).toHaveProperty(EModelEndpoint.azureOpenAI); [EModelEndpoint.azureOpenAI]: expect.objectContaining({
expect(app.locals[EModelEndpoint.azureOpenAI]).toEqual(
expect.objectContaining({
titleConvo: true, titleConvo: true,
titleMethod: 'completion', titleMethod: 'completion',
titleModel: 'gpt-4', titleModel: 'gpt-4',
titlePrompt: 'Azure title prompt', titlePrompt: 'Azure title prompt',
titlePromptTemplate: 'Azure conversation: {{context}}', titlePromptTemplate: 'Azure conversation: {{context}}',
}), }),
}),
); );
}); });
@ -634,10 +665,11 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(app.locals).toHaveProperty(EModelEndpoint.agents); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals[EModelEndpoint.agents]).toMatchObject({ expect.objectContaining({
[EModelEndpoint.agents]: expect.objectContaining({
disableBuilder: false, disableBuilder: false,
titleConvo: true, titleConvo: true,
titleModel: 'gpt-4', titleModel: 'gpt-4',
@ -645,8 +677,13 @@ describe('AppService', () => {
titlePrompt: 'Generate a descriptive title for this agent conversation', titlePrompt: 'Generate a descriptive title for this agent conversation',
titlePromptTemplate: 'Agent conversation summary: {{content}}', titlePromptTemplate: 'Agent conversation summary: {{content}}',
recursionLimit: 15, recursionLimit: 15,
capabilities: expect.arrayContaining([AgentCapabilities.tools, AgentCapabilities.actions]), capabilities: expect.arrayContaining([
}); AgentCapabilities.tools,
AgentCapabilities.actions,
]),
}),
}),
);
}); });
it('should handle missing title configuration options with defaults', async () => { it('should handle missing title configuration options with defaults', async () => {
@ -661,16 +698,21 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(app.locals).toHaveProperty(EModelEndpoint.openAI); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals[EModelEndpoint.openAI]).toMatchObject({ expect.objectContaining({
[EModelEndpoint.openAI]: expect.objectContaining({
titleConvo: true, titleConvo: true,
}); }),
// Check that the optional fields are undefined when not provided }),
expect(app.locals[EModelEndpoint.openAI].titlePrompt).toBeUndefined(); );
expect(app.locals[EModelEndpoint.openAI].titlePromptTemplate).toBeUndefined();
expect(app.locals[EModelEndpoint.openAI].titleMethod).toBeUndefined(); // Verify that optional fields are not set when not provided
const initCall = initializeAppConfig.mock.calls[0][0];
expect(initCall[EModelEndpoint.openAI].titlePrompt).toBeUndefined();
expect(initCall[EModelEndpoint.openAI].titlePromptTemplate).toBeUndefined();
expect(initCall[EModelEndpoint.openAI].titleMethod).toBeUndefined();
}); });
it('should correctly configure titleEndpoint when specified', async () => { it('should correctly configure titleEndpoint when specified', async () => {
@ -691,23 +733,24 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(initializeAppConfig).toHaveBeenCalledWith(
expect.objectContaining({
// Check OpenAI endpoint has titleEndpoint // Check OpenAI endpoint has titleEndpoint
expect(app.locals).toHaveProperty(EModelEndpoint.openAI); [EModelEndpoint.openAI]: expect.objectContaining({
expect(app.locals[EModelEndpoint.openAI]).toMatchObject({
titleConvo: true, titleConvo: true,
titleModel: 'gpt-3.5-turbo', titleModel: 'gpt-3.5-turbo',
titleEndpoint: EModelEndpoint.anthropic, titleEndpoint: EModelEndpoint.anthropic,
titlePrompt: 'Generate a concise title', titlePrompt: 'Generate a concise title',
}); }),
// Check Agents endpoint has titleEndpoint // Check Agents endpoint has titleEndpoint
expect(app.locals).toHaveProperty(EModelEndpoint.agents); [EModelEndpoint.agents]: expect.objectContaining({
expect(app.locals[EModelEndpoint.agents]).toMatchObject({
titleEndpoint: 'custom-provider', titleEndpoint: 'custom-provider',
titleMethod: 'structured', titleMethod: 'structured',
}); }),
}),
);
}); });
it('should correctly configure all endpoint when specified', async () => { it('should correctly configure all endpoint when specified', async () => {
@ -731,11 +774,12 @@ describe('AppService', () => {
}), }),
); );
await AppService(app); await AppService();
expect(initializeAppConfig).toHaveBeenCalledWith(
expect.objectContaining({
// Check that 'all' endpoint config is loaded // Check that 'all' endpoint config is loaded
expect(app.locals).toHaveProperty('all'); all: expect.objectContaining({
expect(app.locals.all).toMatchObject({
titleConvo: true, titleConvo: true,
titleModel: 'gpt-4o-mini', titleModel: 'gpt-4o-mini',
titleMethod: 'structured', titleMethod: 'structured',
@ -743,27 +787,27 @@ describe('AppService', () => {
titlePromptTemplate: 'Default template: {{conversation}}', titlePromptTemplate: 'Default template: {{conversation}}',
titleEndpoint: EModelEndpoint.anthropic, titleEndpoint: EModelEndpoint.anthropic,
streamRate: 50, streamRate: 50,
}); }),
// Check that OpenAI endpoint has its own config // Check that OpenAI endpoint has its own config
expect(app.locals).toHaveProperty(EModelEndpoint.openAI); [EModelEndpoint.openAI]: expect.objectContaining({
expect(app.locals[EModelEndpoint.openAI]).toMatchObject({
titleConvo: true, titleConvo: true,
titleModel: 'gpt-3.5-turbo', titleModel: 'gpt-3.5-turbo',
}); }),
}),
);
}); });
}); });
describe('AppService updating app.locals and issuing warnings', () => { describe('AppService updating app config and issuing warnings', () => {
let app;
let initialEnv; let initialEnv;
const { initializeAppConfig } = require('./Config/getAppConfig');
beforeEach(() => { beforeEach(() => {
// Store initial environment variables to restore them after each test // Store initial environment variables to restore them after each test
initialEnv = { ...process.env }; initialEnv = { ...process.env };
app = { locals: {} };
process.env.CDN_PROVIDER = undefined; process.env.CDN_PROVIDER = undefined;
jest.clearAllMocks();
}); });
afterEach(() => { afterEach(() => {
@ -771,26 +815,27 @@ describe('AppService updating app.locals and issuing warnings', () => {
process.env = { ...initialEnv }; process.env = { ...initialEnv };
}); });
it('should update app.locals with default values if loadCustomConfig returns undefined', async () => { it('should initialize app config with default values if loadCustomConfig returns undefined', async () => {
// Mock loadCustomConfig to return undefined // Mock loadCustomConfig to return undefined
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(undefined)); require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(undefined));
await AppService(app); await AppService();
expect(app.locals).toBeDefined(); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals.paths).toBeDefined();
expect(app.locals.config).toEqual({});
expect(app.locals.fileStrategy).toEqual(FileSources.local);
expect(app.locals.socialLogins).toEqual(defaultSocialLogins);
expect(app.locals.balance).toEqual(
expect.objectContaining({ expect.objectContaining({
paths: expect.anything(),
config: {},
fileStrategy: FileSources.local,
socialLogins: defaultSocialLogins,
balance: expect.objectContaining({
enabled: false, enabled: false,
startBalance: undefined, startBalance: undefined,
}), }),
}),
); );
}); });
it('should update app.locals with values from loadCustomConfig', async () => { it('should initialize app config with values from loadCustomConfig', async () => {
// Mock loadCustomConfig to return a specific config object with a complete balance config // Mock loadCustomConfig to return a specific config object with a complete balance config
const customConfig = { const customConfig = {
fileStrategy: 'firebase', fileStrategy: 'firebase',
@ -808,17 +853,20 @@ describe('AppService updating app.locals and issuing warnings', () => {
Promise.resolve(customConfig), Promise.resolve(customConfig),
); );
await AppService(app); await AppService();
expect(app.locals).toBeDefined(); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals.paths).toBeDefined(); expect.objectContaining({
expect(app.locals.config).toEqual(customConfig); paths: expect.anything(),
expect(app.locals.fileStrategy).toEqual(customConfig.fileStrategy); config: customConfig,
expect(app.locals.socialLogins).toEqual(customConfig.registration.socialLogins); fileStrategy: customConfig.fileStrategy,
expect(app.locals.balance).toEqual(customConfig.balance); socialLogins: customConfig.registration.socialLogins,
balance: customConfig.balance,
}),
);
}); });
it('should apply the assistants endpoint configuration correctly to app.locals', async () => { it('should apply the assistants endpoint configuration correctly to app config', async () => {
const mockConfig = { const mockConfig = {
endpoints: { endpoints: {
assistants: { assistants: {
@ -831,16 +879,22 @@ describe('AppService updating app.locals and issuing warnings', () => {
}; };
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig)); require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
const app = { locals: {} }; await AppService();
await AppService(app);
expect(app.locals).toHaveProperty('assistants'); expect(initializeAppConfig).toHaveBeenCalledWith(
const { assistants } = app.locals; expect.objectContaining({
expect(assistants.disableBuilder).toBe(true); assistants: expect.objectContaining({
expect(assistants.pollIntervalMs).toBe(5000); disableBuilder: true,
expect(assistants.timeoutMs).toBe(30000); pollIntervalMs: 5000,
expect(assistants.supportedIds).toEqual(['id1', 'id2']); timeoutMs: 30000,
expect(assistants.excludedIds).toBeUndefined(); supportedIds: ['id1', 'id2'],
}),
}),
);
// Verify excludedIds is undefined when not provided
const initCall = initializeAppConfig.mock.calls[0][0];
expect(initCall.assistants.excludedIds).toBeUndefined();
}); });
it('should log a warning when both supportedIds and excludedIds are provided', async () => { it('should log a warning when both supportedIds and excludedIds are provided', async () => {
@ -857,8 +911,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
}; };
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig)); require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
const app = { locals: {} }; await require('./AppService')();
await require('./AppService')(app);
const { logger } = require('~/config'); const { logger } = require('~/config');
expect(logger.warn).toHaveBeenCalledWith( expect(logger.warn).toHaveBeenCalledWith(
@ -879,8 +932,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
}; };
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig)); require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
const app = { locals: {} }; await require('./AppService')();
await require('./AppService')(app);
const { logger } = require('~/config'); const { logger } = require('~/config');
expect(logger.warn).toHaveBeenCalledWith( expect(logger.warn).toHaveBeenCalledWith(
@ -905,8 +957,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
process.env[varInfo.key] = 'test'; process.env[varInfo.key] = 'test';
}); });
const app = { locals: {} }; await require('./AppService')();
await require('./AppService')(app);
const { logger } = require('~/config'); const { logger } = require('~/config');
deprecatedAzureVariables.forEach(({ key, description }) => { deprecatedAzureVariables.forEach(({ key, description }) => {
@ -931,8 +982,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
process.env[varInfo.key] = 'test'; process.env[varInfo.key] = 'test';
}); });
const app = { locals: {} }; await require('./AppService')();
await require('./AppService')(app);
const { logger } = require('~/config'); const { logger } = require('~/config');
conflictingAzureVariables.forEach(({ key }) => { conflictingAzureVariables.forEach(({ key }) => {
@ -959,16 +1009,19 @@ describe('AppService updating app.locals and issuing warnings', () => {
process.env.OCR_API_KEY_CUSTOM_VAR_NAME = 'actual-api-key'; process.env.OCR_API_KEY_CUSTOM_VAR_NAME = 'actual-api-key';
process.env.OCR_BASEURL_CUSTOM_VAR_NAME = 'https://actual-ocr-url.com'; process.env.OCR_BASEURL_CUSTOM_VAR_NAME = 'https://actual-ocr-url.com';
// Initialize app await AppService();
const app = { locals: {} };
await AppService(app);
// Verify that the raw string references were preserved and not interpolated // Verify that the raw string references were preserved and not interpolated
expect(app.locals.ocr).toBeDefined(); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals.ocr.apiKey).toEqual('${OCR_API_KEY_CUSTOM_VAR_NAME}'); expect.objectContaining({
expect(app.locals.ocr.baseURL).toEqual('${OCR_BASEURL_CUSTOM_VAR_NAME}'); ocr: expect.objectContaining({
expect(app.locals.ocr.strategy).toEqual('mistral_ocr'); apiKey: '${OCR_API_KEY_CUSTOM_VAR_NAME}',
expect(app.locals.ocr.mistralModel).toEqual('mistral-medium'); baseURL: '${OCR_BASEURL_CUSTOM_VAR_NAME}',
strategy: 'mistral_ocr',
mistralModel: 'mistral-medium',
}),
}),
);
}); });
it('should correctly configure peoplePicker permissions when specified', async () => { it('should correctly configure peoplePicker permissions when specified', async () => {
@ -984,15 +1037,19 @@ describe('AppService updating app.locals and issuing warnings', () => {
require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig)); require('./Config/loadCustomConfig').mockImplementationOnce(() => Promise.resolve(mockConfig));
const app = { locals: {} }; await AppService();
await AppService(app);
// Check that interface config includes the permissions // Check that interface config includes the permissions
expect(app.locals.interfaceConfig.peoplePicker).toBeDefined(); expect(initializeAppConfig).toHaveBeenCalledWith(
expect(app.locals.interfaceConfig.peoplePicker).toMatchObject({ expect.objectContaining({
interfaceConfig: expect.objectContaining({
peoplePicker: expect.objectContaining({
users: true, users: true,
groups: true, groups: true,
roles: true, roles: true,
}); }),
}),
}),
);
}); });
}); });