Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

util.config.test.ts 4.9 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  1. import * as fs from 'fs';
  2. import yaml from 'js-yaml';
  3. import * as os from 'os';
  4. import * as path from 'path';
  5. import type { UnifiedConfig } from '../src/types';
  6. import {
  7. getConfigDirectoryPath,
  8. setConfigDirectoryPath,
  9. writePromptfooConfig,
  10. } from '../src/util/config';
  11. jest.mock('os');
  12. jest.mock('fs');
  13. jest.mock('js-yaml');
  14. describe('config', () => {
  15. const mockHomedir = '/mock/home';
  16. const defaultConfigPath = path.join(mockHomedir, '.promptfoo');
  17. beforeEach(() => {
  18. jest.resetAllMocks();
  19. jest.mocked(os.homedir).mockReturnValue(mockHomedir);
  20. jest.mocked(fs.existsSync).mockReturnValue(false);
  21. delete process.env.PROMPTFOO_CONFIG_DIR;
  22. });
  23. describe('getConfigDirectoryPath', () => {
  24. it('returns default path when no custom path is set', () => {
  25. expect(getConfigDirectoryPath()).toBe(defaultConfigPath);
  26. });
  27. it('does not create directory when createIfNotExists is false', () => {
  28. getConfigDirectoryPath(false);
  29. expect(fs.mkdirSync).not.toHaveBeenCalled();
  30. });
  31. it('creates directory when createIfNotExists is true and directory does not exist', () => {
  32. getConfigDirectoryPath(true);
  33. expect(fs.mkdirSync).toHaveBeenCalledWith(defaultConfigPath, { recursive: true });
  34. });
  35. it('does not create directory when it already exists', () => {
  36. jest.mocked(fs.existsSync).mockReturnValue(true);
  37. getConfigDirectoryPath(true);
  38. expect(fs.mkdirSync).not.toHaveBeenCalled();
  39. });
  40. });
  41. describe('setConfigDirectoryPath', () => {
  42. it('updates the config directory path', () => {
  43. const newPath = '/new/config/path';
  44. setConfigDirectoryPath(newPath);
  45. expect(getConfigDirectoryPath()).toBe(newPath);
  46. });
  47. it('overrides the environment variable', () => {
  48. const envPath = '/env/path';
  49. const newPath = '/new/path';
  50. process.env.PROMPTFOO_CONFIG_DIR = envPath;
  51. setConfigDirectoryPath(newPath);
  52. expect(getConfigDirectoryPath()).toBe(newPath);
  53. });
  54. });
  55. });
  56. describe('writePromptfooConfig', () => {
  57. const mockOutputPath = '/mock/output/path.yaml';
  58. beforeEach(() => {
  59. jest.resetAllMocks();
  60. });
  61. it('writes a basic config to the specified path', () => {
  62. const mockConfig: Partial<UnifiedConfig> = { description: 'Test config' };
  63. const mockYaml = 'description: Test config\n';
  64. jest.mocked(yaml.dump).mockReturnValue(mockYaml);
  65. writePromptfooConfig(mockConfig, mockOutputPath);
  66. expect(fs.writeFileSync).toHaveBeenCalledWith(mockOutputPath, mockYaml);
  67. });
  68. it('orders the keys of the config correctly', () => {
  69. const mockConfig: Partial<UnifiedConfig> = {
  70. tests: [{ assert: [{ type: 'equals', value: 'test assertion' }] }],
  71. description: 'Test config',
  72. prompts: ['prompt1'],
  73. providers: ['provider1'],
  74. defaultTest: { assert: [{ type: 'equals', value: 'default assertion' }] },
  75. };
  76. writePromptfooConfig(mockConfig, mockOutputPath);
  77. const dumpCall = jest.mocked(yaml.dump).mock.calls[0][0];
  78. const keys = Object.keys(dumpCall);
  79. expect(keys).toEqual(['description', 'prompts', 'providers', 'defaultTest', 'tests']);
  80. });
  81. it('uses js-yaml to dump the config with skipInvalid option', () => {
  82. const mockConfig: Partial<UnifiedConfig> = { description: 'Test config' };
  83. writePromptfooConfig(mockConfig, mockOutputPath);
  84. expect(yaml.dump).toHaveBeenCalledWith(expect.anything(), { skipInvalid: true });
  85. });
  86. it('handles empty config', () => {
  87. const mockConfig: Partial<UnifiedConfig> = {};
  88. writePromptfooConfig(mockConfig, mockOutputPath);
  89. expect(fs.writeFileSync).toHaveBeenCalledWith(mockOutputPath, undefined);
  90. expect(yaml.dump).toHaveBeenCalledWith({}, { skipInvalid: true });
  91. });
  92. it('preserves all fields of the UnifiedConfig', () => {
  93. const mockConfig: Partial<UnifiedConfig> = {
  94. description: 'Full config test',
  95. prompts: ['prompt1', 'prompt2'],
  96. providers: ['provider1', 'provider2'],
  97. defaultTest: { assert: [{ type: 'equals', value: 'default assertion' }] },
  98. tests: [
  99. { assert: [{ type: 'equals', value: 'test assertion 1' }] },
  100. { assert: [{ type: 'equals', value: 'test assertion 2' }] },
  101. ],
  102. outputPath: './output',
  103. };
  104. writePromptfooConfig(mockConfig, mockOutputPath);
  105. const dumpCall = jest.mocked(yaml.dump).mock.calls[0][0];
  106. expect(dumpCall).toEqual(expect.objectContaining(mockConfig));
  107. });
  108. it('handles config with undefined values', () => {
  109. const mockConfig: Partial<UnifiedConfig> = {
  110. description: 'Config with undefined',
  111. prompts: undefined,
  112. providers: ['provider1'],
  113. };
  114. writePromptfooConfig(mockConfig, mockOutputPath);
  115. const dumpCall = jest.mocked(yaml.dump).mock.calls[0][0];
  116. expect(dumpCall).toHaveProperty('description', 'Config with undefined');
  117. expect(dumpCall).toHaveProperty('providers', ['provider1']);
  118. expect(dumpCall).not.toHaveProperty('prompts');
  119. });
  120. });
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...