aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-01-09 21:02:36 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-01-09 22:17:13 +0100
commit602bce34c8f7c2f8c68dd18f29243e467ed0fb08 (patch)
tree6ac9dab6b892faef42c8d2bb760e4b556756dc39
parentbuild: Add prettier (diff)
downloadsophie-602bce34c8f7c2f8c68dd18f29243e467ed0fb08.tar.gz
sophie-602bce34c8f7c2f8c68dd18f29243e467ed0fb08.tar.zst
sophie-602bce34c8f7c2f8c68dd18f29243e467ed0fb08.zip
build: Add eslint-plugin-jest
Signed-off-by: Kristóf Marussy <kristof@marussy.com>
-rw-r--r--.eslintrc.cjs4
-rw-r--r--package.json1
-rw-r--r--packages/main/src/controllers/__tests__/initConfig.spec.ts18
-rw-r--r--packages/main/src/controllers/__tests__/initNativeTheme.spec.ts4
-rw-r--r--packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts29
-rw-r--r--yarn.lock20
6 files changed, 50 insertions, 26 deletions
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 1301de4..5bb3c21 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -9,6 +9,8 @@ module.exports = {
9 'airbnb/hooks', 9 'airbnb/hooks',
10 'plugin:@typescript-eslint/recommended', 10 'plugin:@typescript-eslint/recommended',
11 'plugin:@typescript-eslint/recommended-requiring-type-checking', 11 'plugin:@typescript-eslint/recommended-requiring-type-checking',
12 'plugin:jest/recommended',
13 'plugin:jest/style',
12 'plugin:prettier/recommended', 14 'plugin:prettier/recommended',
13 ], 15 ],
14 env: { 16 env: {
@@ -67,6 +69,8 @@ module.exports = {
67 '@typescript-eslint/no-non-null-assertion': 'off', 69 '@typescript-eslint/no-non-null-assertion': 'off',
68 // Jest mocks use unbound method references. 70 // Jest mocks use unbound method references.
69 '@typescript-eslint/unbound-method': 'off', 71 '@typescript-eslint/unbound-method': 'off',
72 // We can't turn this on yet, because it doesn't understand `mocked` from `jest-mock`.
73 // 'jest/unbound-method': 'error',
70 }, 74 },
71 }, 75 },
72 { 76 {
diff --git a/package.json b/package.json
index 22cc738..5515d3d 100644
--- a/package.json
+++ b/package.json
@@ -68,6 +68,7 @@
68 "eslint-formatter-gitlab": "^3.0.0", 68 "eslint-formatter-gitlab": "^3.0.0",
69 "eslint-import-resolver-typescript": "^2.5.0", 69 "eslint-import-resolver-typescript": "^2.5.0",
70 "eslint-plugin-import": "^2.25.4", 70 "eslint-plugin-import": "^2.25.4",
71 "eslint-plugin-jest": "^25.3.4",
71 "eslint-plugin-jsx-a11y": "^6.5.1", 72 "eslint-plugin-jsx-a11y": "^6.5.1",
72 "eslint-plugin-prettier": "^4.0.0", 73 "eslint-plugin-prettier": "^4.0.0",
73 "eslint-plugin-react": "^7.28.0", 74 "eslint-plugin-react": "^7.28.0",
diff --git a/packages/main/src/controllers/__tests__/initConfig.spec.ts b/packages/main/src/controllers/__tests__/initConfig.spec.ts
index 7b6d6ab..9a5f85e 100644
--- a/packages/main/src/controllers/__tests__/initConfig.spec.ts
+++ b/packages/main/src/controllers/__tests__/initConfig.spec.ts
@@ -56,7 +56,7 @@ describe('when initializing', () => {
56 56
57 it('should create a new config file', async () => { 57 it('should create a new config file', async () => {
58 await initConfig(config, persistenceService); 58 await initConfig(config, persistenceService);
59 expect(persistenceService.writeConfig).toBeCalledTimes(1); 59 expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1);
60 }); 60 });
61 61
62 it('should bail if there is an an error creating the config file', async () => { 62 it('should bail if there is an an error creating the config file', async () => {
@@ -81,7 +81,7 @@ describe('when initializing', () => {
81 81
82 it('should read the existing config file is there is one', async () => { 82 it('should read the existing config file is there is one', async () => {
83 await initConfig(config, persistenceService); 83 await initConfig(config, persistenceService);
84 expect(persistenceService.writeConfig).not.toBeCalled(); 84 expect(persistenceService.writeConfig).not.toHaveBeenCalled();
85 expect(config.themeSource).toBe('dark'); 85 expect(config.themeSource).toBe('dark');
86 }); 86 });
87 87
@@ -138,14 +138,14 @@ describe('when it has loaded the config', () => {
138 jest.advanceTimersByTime(lessThanThrottleMs); 138 jest.advanceTimersByTime(lessThanThrottleMs);
139 config.setThemeSource('light'); 139 config.setThemeSource('light');
140 jest.advanceTimersByTime(throttleMs); 140 jest.advanceTimersByTime(throttleMs);
141 expect(persistenceService.writeConfig).toBeCalledTimes(1); 141 expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1);
142 }); 142 });
143 143
144 it('should handle config writing errors gracefully', () => { 144 it('should handle config writing errors gracefully', () => {
145 mocked(persistenceService.writeConfig).mockRejectedValue(new Error('boo')); 145 mocked(persistenceService.writeConfig).mockRejectedValue(new Error('boo'));
146 config.setThemeSource('dark'); 146 config.setThemeSource('dark');
147 jest.advanceTimersByTime(throttleMs); 147 jest.advanceTimersByTime(throttleMs);
148 expect(persistenceService.writeConfig).toBeCalledTimes(1); 148 expect(persistenceService.writeConfig).toHaveBeenCalledTimes(1);
149 }); 149 });
150 150
151 it('should read the config file when it has changed', async () => { 151 it('should read the config file when it has changed', async () => {
@@ -157,7 +157,7 @@ describe('when it has loaded the config', () => {
157 }); 157 });
158 await configChangedCallback(); 158 await configChangedCallback();
159 // Do not write back the changes we have just read. 159 // Do not write back the changes we have just read.
160 expect(persistenceService.writeConfig).not.toBeCalled(); 160 expect(persistenceService.writeConfig).not.toHaveBeenCalled();
161 expect(config.themeSource).toBe('dark'); 161 expect(config.themeSource).toBe('dark');
162 }); 162 });
163 163
@@ -172,9 +172,9 @@ describe('when it has loaded the config', () => {
172 expect(config.themeSource).not.toBe(-1); 172 expect(config.themeSource).not.toBe(-1);
173 }); 173 });
174 174
175 it('should handle config writing errors gracefully', async () => { 175 it('should handle config reading errors gracefully', async () => {
176 mocked(persistenceService.readConfig).mockRejectedValue(new Error('boo')); 176 mocked(persistenceService.readConfig).mockRejectedValue(new Error('boo'));
177 await configChangedCallback(); 177 await expect(configChangedCallback()).resolves.not.toThrow();
178 }); 178 });
179 179
180 describe('when it was disposed', () => { 180 describe('when it was disposed', () => {
@@ -183,13 +183,13 @@ describe('when it has loaded the config', () => {
183 }); 183 });
184 184
185 it('should dispose the watcher', () => { 185 it('should dispose the watcher', () => {
186 expect(watcherDisposer).toBeCalled(); 186 expect(watcherDisposer).toHaveBeenCalled();
187 }); 187 });
188 188
189 it('should not listen to store changes any more', () => { 189 it('should not listen to store changes any more', () => {
190 config.setThemeSource('dark'); 190 config.setThemeSource('dark');
191 jest.advanceTimersByTime(2 * throttleMs); 191 jest.advanceTimersByTime(2 * throttleMs);
192 expect(persistenceService.writeConfig).not.toBeCalled(); 192 expect(persistenceService.writeConfig).not.toHaveBeenCalled();
193 }); 193 });
194 }); 194 });
195}); 195});
diff --git a/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts b/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts
index d4068af..16acca5 100644
--- a/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts
+++ b/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts
@@ -49,7 +49,7 @@ beforeEach(() => {
49}); 49});
50 50
51it('should register a nativeTheme updated listener', () => { 51it('should register a nativeTheme updated listener', () => {
52 expect(nativeTheme.on).toBeCalledWith('updated', expect.anything()); 52 expect(nativeTheme.on).toHaveBeenCalledWith('updated', expect.anything());
53}); 53});
54 54
55it('should synchronize themeSource changes to the nativeTheme', () => { 55it('should synchronize themeSource changes to the nativeTheme', () => {
@@ -71,5 +71,5 @@ it('should remove the listener on dispose', () => {
71 ([event]) => event === 'updated', 71 ([event]) => event === 'updated',
72 )![1]; 72 )![1];
73 disposeSut(); 73 disposeSut();
74 expect(nativeTheme.off).toBeCalledWith('updated', listener); 74 expect(nativeTheme.off).toHaveBeenCalledWith('updated', listener);
75}); 75});
diff --git a/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts b/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts
index f63c3f6..b0af280 100644
--- a/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts
+++ b/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts
@@ -108,10 +108,10 @@ describe('SharedStoreConnector', () => {
108 it('should request a snapshot from the main process', async () => { 108 it('should request a snapshot from the main process', async () => {
109 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot); 109 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot);
110 await sut.onSharedStoreChange(listener); 110 await sut.onSharedStoreChange(listener);
111 expect(ipcRenderer.invoke).toBeCalledWith( 111 expect(ipcRenderer.invoke).toHaveBeenCalledWith(
112 RendererToMainIpcMessage.GetSharedStoreSnapshot, 112 RendererToMainIpcMessage.GetSharedStoreSnapshot,
113 ); 113 );
114 expect(listener.onSnapshot).toBeCalledWith(snapshot); 114 expect(listener.onSnapshot).toHaveBeenCalledWith(snapshot);
115 }); 115 });
116 116
117 it('should catch IPC errors without exposing them', async () => { 117 it('should catch IPC errors without exposing them', async () => {
@@ -119,7 +119,7 @@ describe('SharedStoreConnector', () => {
119 await expect( 119 await expect(
120 sut.onSharedStoreChange(listener), 120 sut.onSharedStoreChange(listener),
121 ).rejects.not.toHaveProperty('message', expect.stringMatching(/s3cr3t/)); 121 ).rejects.not.toHaveProperty('message', expect.stringMatching(/s3cr3t/));
122 expect(listener.onSnapshot).not.toBeCalled(); 122 expect(listener.onSnapshot).not.toHaveBeenCalled();
123 }); 123 });
124 124
125 it('should not pass on invalid snapshots', async () => { 125 it('should not pass on invalid snapshots', async () => {
@@ -127,28 +127,28 @@ describe('SharedStoreConnector', () => {
127 await expect(sut.onSharedStoreChange(listener)).rejects.toBeInstanceOf( 127 await expect(sut.onSharedStoreChange(listener)).rejects.toBeInstanceOf(
128 Error, 128 Error,
129 ); 129 );
130 expect(listener.onSnapshot).not.toBeCalled(); 130 expect(listener.onSnapshot).not.toHaveBeenCalled();
131 }); 131 });
132 }); 132 });
133 133
134 describe('dispatchAction', () => { 134 describe('dispatchAction', () => {
135 it('should dispatch valid actions', () => { 135 it('should dispatch valid actions', () => {
136 sut.dispatchAction(action); 136 sut.dispatchAction(action);
137 expect(ipcRenderer.send).toBeCalledWith( 137 expect(ipcRenderer.send).toHaveBeenCalledWith(
138 RendererToMainIpcMessage.DispatchAction, 138 RendererToMainIpcMessage.DispatchAction,
139 action, 139 action,
140 ); 140 );
141 }); 141 });
142 142
143 it('should not dispatch invalid actions', () => { 143 it('should not dispatch invalid actions', () => {
144 expect(() => sut.dispatchAction(invalidAction)).toThrowError(); 144 expect(() => sut.dispatchAction(invalidAction)).toThrow();
145 expect(ipcRenderer.send).not.toBeCalled(); 145 expect(ipcRenderer.send).not.toHaveBeenCalled();
146 }); 146 });
147 }); 147 });
148 148
149 describe('when no listener is registered', () => { 149 describe('when no listener is registered', () => {
150 it('should discard the received patch without any error', () => { 150 it('should discard the received patch without any error', () => {
151 onSharedStorePatch(event, patch); 151 expect(() => onSharedStorePatch(event, patch)).not.toThrow();
152 }); 152 });
153 }); 153 });
154 154
@@ -163,9 +163,10 @@ describe('SharedStoreConnector', () => {
163 function itDoesNotPassPatchesToTheListener( 163 function itDoesNotPassPatchesToTheListener(
164 name = 'should not pass patches to the listener', 164 name = 'should not pass patches to the listener',
165 ): void { 165 ): void {
166 // eslint-disable-next-line jest/valid-title -- Title is a string parameter.
166 it(name, () => { 167 it(name, () => {
167 onSharedStorePatch(event, patch); 168 onSharedStorePatch(event, patch);
168 expect(listener.onPatch).not.toBeCalled(); 169 expect(listener.onPatch).not.toHaveBeenCalled();
169 }); 170 });
170 } 171 }
171 172
@@ -177,14 +178,14 @@ describe('SharedStoreConnector', () => {
177 178
178 it('should pass patches to the listener', () => { 179 it('should pass patches to the listener', () => {
179 onSharedStorePatch(event, patch); 180 onSharedStorePatch(event, patch);
180 expect(listener.onPatch).toBeCalledWith(patch); 181 expect(listener.onPatch).toHaveBeenCalledWith(patch);
181 }); 182 });
182 183
183 it('should catch listener errors', () => { 184 it('should catch listener errors', () => {
184 mocked(listener.onPatch).mockImplementation(() => { 185 mocked(listener.onPatch).mockImplementation(() => {
185 throw new Error(); 186 throw new Error();
186 }); 187 });
187 onSharedStorePatch(event, patch); 188 expect(() => onSharedStorePatch(event, patch)).not.toThrow();
188 }); 189 });
189 190
190 itRefusesToRegisterAnotherListener(); 191 itRefusesToRegisterAnotherListener();
@@ -264,17 +265,17 @@ describe('SharedStoreConnector', () => {
264 it('should fetch a second snapshot', async () => { 265 it('should fetch a second snapshot', async () => {
265 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot2); 266 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot2);
266 await sut.onSharedStoreChange(listener2); 267 await sut.onSharedStoreChange(listener2);
267 expect(ipcRenderer.invoke).toBeCalledWith( 268 expect(ipcRenderer.invoke).toHaveBeenCalledWith(
268 RendererToMainIpcMessage.GetSharedStoreSnapshot, 269 RendererToMainIpcMessage.GetSharedStoreSnapshot,
269 ); 270 );
270 expect(listener2.onSnapshot).toBeCalledWith(snapshot2); 271 expect(listener2.onSnapshot).toHaveBeenCalledWith(snapshot2);
271 }); 272 });
272 273
273 it('should pass the second snapshot to the new listener', async () => { 274 it('should pass the second snapshot to the new listener', async () => {
274 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot2); 275 mocked(ipcRenderer.invoke).mockResolvedValueOnce(snapshot2);
275 await sut.onSharedStoreChange(listener2); 276 await sut.onSharedStoreChange(listener2);
276 onSharedStorePatch(event, patch); 277 onSharedStorePatch(event, patch);
277 expect(listener2.onPatch).toBeCalledWith(patch); 278 expect(listener2.onPatch).toHaveBeenCalledWith(patch);
278 }); 279 });
279 }); 280 });
280}); 281});
diff --git a/yarn.lock b/yarn.lock
index 4d051ac..3b96a84 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1699,7 +1699,7 @@ __metadata:
1699 languageName: node 1699 languageName: node
1700 linkType: hard 1700 linkType: hard
1701 1701
1702"@typescript-eslint/experimental-utils@npm:5.9.0": 1702"@typescript-eslint/experimental-utils@npm:5.9.0, @typescript-eslint/experimental-utils@npm:^5.0.0":
1703 version: 5.9.0 1703 version: 5.9.0
1704 resolution: "@typescript-eslint/experimental-utils@npm:5.9.0" 1704 resolution: "@typescript-eslint/experimental-utils@npm:5.9.0"
1705 dependencies: 1705 dependencies:
@@ -4080,6 +4080,23 @@ __metadata:
4080 languageName: node 4080 languageName: node
4081 linkType: hard 4081 linkType: hard
4082 4082
4083"eslint-plugin-jest@npm:^25.3.4":
4084 version: 25.3.4
4085 resolution: "eslint-plugin-jest@npm:25.3.4"
4086 dependencies:
4087 "@typescript-eslint/experimental-utils": ^5.0.0
4088 peerDependencies:
4089 "@typescript-eslint/eslint-plugin": ^4.0.0 || ^5.0.0
4090 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
4091 peerDependenciesMeta:
4092 "@typescript-eslint/eslint-plugin":
4093 optional: true
4094 jest:
4095 optional: true
4096 checksum: 1ad168a25678025ac3b7f637683ae68e49972a091b7a57ab5e41ceadf7f9807b112855c9b0d38a332a033289a224bff0ae2c8d9a05326ca1d6c3007048794898
4097 languageName: node
4098 linkType: hard
4099
4083"eslint-plugin-jsx-a11y@npm:^6.5.1": 4100"eslint-plugin-jsx-a11y@npm:^6.5.1":
4084 version: 6.5.1 4101 version: 6.5.1
4085 resolution: "eslint-plugin-jsx-a11y@npm:6.5.1" 4102 resolution: "eslint-plugin-jsx-a11y@npm:6.5.1"
@@ -7992,6 +8009,7 @@ __metadata:
7992 eslint-formatter-gitlab: ^3.0.0 8009 eslint-formatter-gitlab: ^3.0.0
7993 eslint-import-resolver-typescript: ^2.5.0 8010 eslint-import-resolver-typescript: ^2.5.0
7994 eslint-plugin-import: ^2.25.4 8011 eslint-plugin-import: ^2.25.4
8012 eslint-plugin-jest: ^25.3.4
7995 eslint-plugin-jsx-a11y: ^6.5.1 8013 eslint-plugin-jsx-a11y: ^6.5.1
7996 eslint-plugin-prettier: ^4.0.0 8014 eslint-plugin-prettier: ^4.0.0
7997 eslint-plugin-react: ^7.28.0 8015 eslint-plugin-react: ^7.28.0