aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src/controllers/__tests__/initConfig.spec.ts
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-01-27 00:17:22 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-02-08 21:43:17 +0100
commit9546dc2aa39ab096ccc723786e718a739d0bdaf9 (patch)
tree9c3afc6155cc59f6dd1235397230aaa15a5f8cec /packages/main/src/controllers/__tests__/initConfig.spec.ts
parentrefactor: Apply shared store patches in batches (diff)
downloadsophie-9546dc2aa39ab096ccc723786e718a739d0bdaf9.tar.gz
sophie-9546dc2aa39ab096ccc723786e718a739d0bdaf9.tar.zst
sophie-9546dc2aa39ab096ccc723786e718a739d0bdaf9.zip
refactor: Coding conventions
Make sure that files have a default import with the same name as the file whenever possible to reduce surprise. Also shuffles around some file names for better legibility. Signed-off-by: Kristóf Marussy <kristof@marussy.com>
Diffstat (limited to 'packages/main/src/controllers/__tests__/initConfig.spec.ts')
-rw-r--r--packages/main/src/controllers/__tests__/initConfig.spec.ts229
1 files changed, 0 insertions, 229 deletions
diff --git a/packages/main/src/controllers/__tests__/initConfig.spec.ts b/packages/main/src/controllers/__tests__/initConfig.spec.ts
deleted file mode 100644
index fdd22c9..0000000
--- a/packages/main/src/controllers/__tests__/initConfig.spec.ts
+++ /dev/null
@@ -1,229 +0,0 @@
1/*
2 * Copyright (C) 2021-2022 Kristóf Marussy <kristof@marussy.com>
3 *
4 * This file is part of Sophie.
5 *
6 * Sophie is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: AGPL-3.0-only
19 */
20
21import { jest } from '@jest/globals';
22import { mocked } from 'jest-mock';
23import ms from 'ms';
24
25import type ConfigPersistence from '../../infrastructure/ConfigPersistence';
26import { sharedStore, SharedStore } from '../../stores/SharedStore';
27import type Disposer from '../../utils/Disposer';
28import { silenceLogger } from '../../utils/log';
29import initConfig from '../initConfig';
30
31let store: SharedStore;
32const persistenceService: ConfigPersistence = {
33 readConfig: jest.fn(),
34 writeConfig: jest.fn(),
35 watchConfig: jest.fn(),
36};
37const lessThanThrottleMs = ms('0.1s');
38const throttleMs = ms('1s');
39
40beforeAll(() => {
41 jest.useFakeTimers();
42 silenceLogger();
43});
44
45beforeEach(() => {
46 store = sharedStore.create();
47});
48
49describe('when initializing', () => {
50 describe('when there is no config file', () => {
51 beforeEach(() => {
52 mocked(persistenceService.readConfig).mockResolvedValueOnce({
53 found: false,
54 });
55 });
56
57 it('should create a new config file', async () => {
58 await initConfig(store, persistenceService);
59 expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1);
60 });
61
62 it('should bail if there is an an error creating the config file', async () => {
63 mocked(persistenceService.writeConfig).mockRejectedValue(
64 new Error('boo'),
65 );
66 await expect(() =>
67 initConfig(store, persistenceService),
68 ).rejects.toBeInstanceOf(Error);
69 });
70 });
71
72 describe('when there is a valid config file', () => {
73 beforeEach(() => {
74 mocked(persistenceService.readConfig).mockResolvedValueOnce({
75 found: true,
76 data: {
77 // Use a default empty config file to not trigger config rewrite.
78 ...store.config,
79 themeSource: 'dark',
80 },
81 });
82 });
83
84 it('should read the existing config file is there is one', async () => {
85 await initConfig(store, persistenceService);
86 expect(persistenceService.writeConfig).not.toHaveBeenCalled();
87 expect(store.settings.themeSource).toBe('dark');
88 });
89
90 it('should bail if it cannot set up a watcher', async () => {
91 mocked(persistenceService.watchConfig).mockImplementationOnce(() => {
92 throw new Error('boo');
93 });
94 await expect(() =>
95 initConfig(store, persistenceService),
96 ).rejects.toBeInstanceOf(Error);
97 });
98 });
99
100 it('should update the config file if new details are added during read', async () => {
101 mocked(persistenceService.readConfig).mockResolvedValueOnce({
102 found: true,
103 data: {
104 themeSource: 'light',
105 profile: {
106 name: 'Test profile',
107 },
108 },
109 });
110 await initConfig(store, persistenceService);
111 expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1);
112 });
113
114 it('should not apply an invalid config file but should not overwrite it', async () => {
115 mocked(persistenceService.readConfig).mockResolvedValueOnce({
116 found: true,
117 data: {
118 themeSource: -1,
119 },
120 });
121 await initConfig(store, persistenceService);
122 expect(store.settings.themeSource).not.toBe(-1);
123 expect(persistenceService.writeConfig).not.toHaveBeenCalled();
124 });
125
126 it('should bail if it cannot determine whether there is a config file', async () => {
127 mocked(persistenceService.readConfig).mockRejectedValue(new Error('boo'));
128 await expect(() =>
129 initConfig(store, persistenceService),
130 ).rejects.toBeInstanceOf(Error);
131 });
132});
133
134describe('when it has loaded the config', () => {
135 let sutDisposer: Disposer;
136 const watcherDisposer: Disposer = jest.fn();
137 let configChangedCallback: () => Promise<void>;
138
139 beforeEach(async () => {
140 mocked(persistenceService.readConfig).mockResolvedValueOnce({
141 found: true,
142 data: store.config,
143 });
144 mocked(persistenceService.watchConfig).mockReturnValueOnce(watcherDisposer);
145 sutDisposer = await initConfig(store, persistenceService, throttleMs);
146 [[configChangedCallback]] = mocked(
147 persistenceService.watchConfig,
148 ).mock.calls;
149 jest.resetAllMocks();
150 });
151
152 it('should throttle saving changes to the config file', () => {
153 mocked(persistenceService.writeConfig).mockResolvedValue();
154 store.settings.setThemeSource('dark');
155 jest.advanceTimersByTime(lessThanThrottleMs);
156 store.settings.setThemeSource('light');
157 jest.advanceTimersByTime(throttleMs);
158 expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1);
159 });
160
161 it('should handle config writing errors gracefully', () => {
162 mocked(persistenceService.writeConfig).mockRejectedValue(new Error('boo'));
163 store.settings.setThemeSource('dark');
164 jest.advanceTimersByTime(throttleMs);
165 expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1);
166 });
167
168 it('should read the config file when it has changed', async () => {
169 mocked(persistenceService.readConfig).mockResolvedValueOnce({
170 found: true,
171 data: {
172 // Use a default empty config file to not trigger config rewrite.
173 ...store.config,
174 themeSource: 'dark',
175 },
176 });
177 await configChangedCallback();
178 // Do not write back the changes we have just read.
179 expect(persistenceService.writeConfig).not.toHaveBeenCalled();
180 expect(store.settings.themeSource).toBe('dark');
181 });
182
183 it('should update the config file if new details are added', async () => {
184 mocked(persistenceService.readConfig).mockResolvedValueOnce({
185 found: true,
186 data: {
187 themeSource: 'light',
188 profile: {
189 name: 'Test profile',
190 },
191 },
192 });
193 await configChangedCallback();
194 expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1);
195 });
196
197 it('should not apply an invalid config file when it has changed but should not overwrite it', async () => {
198 mocked(persistenceService.readConfig).mockResolvedValueOnce({
199 found: true,
200 data: {
201 themeSource: -1,
202 },
203 });
204 await configChangedCallback();
205 expect(store.settings.themeSource).not.toBe(-1);
206 expect(persistenceService.writeConfig).not.toHaveBeenCalled();
207 });
208
209 it('should handle config reading errors gracefully', async () => {
210 mocked(persistenceService.readConfig).mockRejectedValue(new Error('boo'));
211 await expect(configChangedCallback()).resolves.not.toThrow();
212 });
213
214 describe('when it was disposed', () => {
215 beforeEach(() => {
216 sutDisposer();
217 });
218
219 it('should dispose the watcher', () => {
220 expect(watcherDisposer).toHaveBeenCalled();
221 });
222
223 it('should not listen to store changes any more', () => {
224 store.settings.setThemeSource('dark');
225 jest.advanceTimersByTime(2 * throttleMs);
226 expect(persistenceService.writeConfig).not.toHaveBeenCalled();
227 });
228 });
229});