diff options
Diffstat (limited to 'packages/shared')
-rw-r--r-- | packages/shared/jest.config.js | 4 | ||||
-rw-r--r-- | packages/shared/src/stores/__tests__/ServiceBase.test.ts | 206 |
2 files changed, 210 insertions, 0 deletions
diff --git a/packages/shared/jest.config.js b/packages/shared/jest.config.js new file mode 100644 index 0000000..9aaf344 --- /dev/null +++ b/packages/shared/jest.config.js | |||
@@ -0,0 +1,4 @@ | |||
1 | import baseConfig from '../../config/jest.config.base.js'; | ||
2 | |||
3 | // eslint-disable-next-line unicorn/prefer-export-from -- Can't export from default. | ||
4 | export default baseConfig; | ||
diff --git a/packages/shared/src/stores/__tests__/ServiceBase.test.ts b/packages/shared/src/stores/__tests__/ServiceBase.test.ts new file mode 100644 index 0000000..e7aa078 --- /dev/null +++ b/packages/shared/src/stores/__tests__/ServiceBase.test.ts | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * Copyright (C) 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 | |||
21 | import type { SnapshotIn } from 'mobx-state-tree'; | ||
22 | |||
23 | import Certificate from '../Certificate.js'; | ||
24 | import Profile from '../Profile.js'; | ||
25 | import ServiceBase, { SecurityLabelKind } from '../ServiceBase.js'; | ||
26 | import type { ServiceStateSnapshotIn } from '../ServiceState.js'; | ||
27 | import SharedStoreBase from '../SharedStoreBase.js'; | ||
28 | |||
29 | const testProfile: SnapshotIn<typeof Profile> = { | ||
30 | id: 'testProfile', | ||
31 | settings: { | ||
32 | name: 'test profile', | ||
33 | }, | ||
34 | }; | ||
35 | |||
36 | const testService: SnapshotIn<typeof ServiceBase> = { | ||
37 | id: 'testService', | ||
38 | settings: { | ||
39 | name: 'testService', | ||
40 | url: 'https://example.org', | ||
41 | profile: 'testProfile', | ||
42 | }, | ||
43 | }; | ||
44 | |||
45 | const testCertificate: SnapshotIn<typeof Certificate> = { | ||
46 | data: '-----TEST DATA-----', | ||
47 | issuer: { | ||
48 | commonName: 'Test issuer', | ||
49 | country: '', | ||
50 | state: '', | ||
51 | locality: '', | ||
52 | }, | ||
53 | issuerName: 'Test issuer', | ||
54 | subject: { | ||
55 | commonName: 'Test subject', | ||
56 | country: '', | ||
57 | state: '', | ||
58 | locality: '', | ||
59 | }, | ||
60 | subjectName: 'Test subject', | ||
61 | serialNumber: '123456', | ||
62 | validStart: 1_653_551_516, | ||
63 | validExpiry: 1_685_087_516, | ||
64 | fingerprint: 'sha256/KUIHdVkSTzYmb2PGMotOPDm2ir52G1QyPW6rt6wUjZ0=', | ||
65 | }; | ||
66 | |||
67 | function createTestService( | ||
68 | snapshot: Partial<SnapshotIn<typeof ServiceBase>>, | ||
69 | profileSnapshot?: Partial<SnapshotIn<typeof Profile>>, | ||
70 | ): ServiceBase { | ||
71 | const sharedStore = SharedStoreBase.create({ | ||
72 | profilesById: { | ||
73 | testProfile: { | ||
74 | ...testProfile, | ||
75 | ...profileSnapshot, | ||
76 | }, | ||
77 | }, | ||
78 | servicesById: { | ||
79 | testService: { | ||
80 | ...testService, | ||
81 | ...snapshot, | ||
82 | }, | ||
83 | }, | ||
84 | }); | ||
85 | return sharedStore.servicesById.get(testService.id)!; | ||
86 | } | ||
87 | |||
88 | test.each<{ | ||
89 | state: ServiceStateSnapshotIn; | ||
90 | loading: boolean; | ||
91 | crashed: boolean; | ||
92 | hasError: boolean; | ||
93 | }>([ | ||
94 | { | ||
95 | state: { type: 'initializing' }, | ||
96 | loading: true, | ||
97 | crashed: false, | ||
98 | hasError: false, | ||
99 | }, | ||
100 | { | ||
101 | state: { type: 'loading' }, | ||
102 | loading: true, | ||
103 | crashed: false, | ||
104 | hasError: false, | ||
105 | }, | ||
106 | { | ||
107 | state: { type: 'loaded' }, | ||
108 | loading: false, | ||
109 | crashed: false, | ||
110 | hasError: false, | ||
111 | }, | ||
112 | { | ||
113 | state: { | ||
114 | type: 'failed', | ||
115 | errorCode: 999, | ||
116 | errorDesc: 'Test error', | ||
117 | }, | ||
118 | loading: false, | ||
119 | crashed: false, | ||
120 | hasError: true, | ||
121 | }, | ||
122 | { | ||
123 | state: { | ||
124 | type: 'certificateError', | ||
125 | errorCode: 'Test certificate error', | ||
126 | certificate: testCertificate, | ||
127 | trust: 'pending', | ||
128 | }, | ||
129 | loading: false, | ||
130 | crashed: false, | ||
131 | hasError: true, | ||
132 | }, | ||
133 | { | ||
134 | state: { | ||
135 | type: 'crashed', | ||
136 | reason: 'Test', | ||
137 | exitCode: 255, | ||
138 | }, | ||
139 | loading: false, | ||
140 | crashed: true, | ||
141 | hasError: true, | ||
142 | }, | ||
143 | ])( | ||
144 | 'sets the loaded and error flags when the status is $state', | ||
145 | ({ state, loading, crashed, hasError }) => { | ||
146 | const service = createTestService({ state }); | ||
147 | |||
148 | expect(service.loading).toBe(loading); | ||
149 | expect(service.crashed).toBe(crashed); | ||
150 | expect(service.hasError).toBe(hasError); | ||
151 | expect(service.alwaysShowLocationBar).toBe(hasError); | ||
152 | }, | ||
153 | ); | ||
154 | |||
155 | test.each([ | ||
156 | [undefined, SecurityLabelKind.Empty, false], | ||
157 | ['', SecurityLabelKind.Empty, false], | ||
158 | ['https://example.org', SecurityLabelKind.SecureConnection, false], | ||
159 | ['http://example.org', SecurityLabelKind.NotSecureConnection, true], | ||
160 | ['https:', SecurityLabelKind.InvalidURL, true], | ||
161 | ['file:///etc/shadow', SecurityLabelKind.InvalidURL, true], | ||
162 | ['asdfasdfasdf', SecurityLabelKind.InvalidURL, true], | ||
163 | ])( | ||
164 | 'sets the security label when the url %s is loaded', | ||
165 | ( | ||
166 | url: string | undefined, | ||
167 | labelKind: SecurityLabelKind, | ||
168 | hasWarning: boolean, | ||
169 | ) => { | ||
170 | const service = createTestService({ currentUrl: url }); | ||
171 | |||
172 | expect(service.securityLabel).toBe(labelKind); | ||
173 | expect(service.alwaysShowLocationBar).toBe(hasWarning); | ||
174 | }, | ||
175 | ); | ||
176 | |||
177 | test('shows a certificate error warning if there is a certificate error', () => { | ||
178 | const service = createTestService({ | ||
179 | state: { | ||
180 | type: 'certificateError', | ||
181 | errorCode: 'Test certificate error', | ||
182 | certificate: testCertificate, | ||
183 | trust: 'pending', | ||
184 | }, | ||
185 | }); | ||
186 | |||
187 | expect(service.securityLabel).toBe(SecurityLabelKind.CertificateError); | ||
188 | expect(service.alwaysShowLocationBar).toBe(true); | ||
189 | }); | ||
190 | |||
191 | test('does not trust an untrusted certificate', () => { | ||
192 | const service = createTestService({}); | ||
193 | |||
194 | expect(service.isCertificateTemporarilyTrusted(testCertificate)).toBe(false); | ||
195 | }); | ||
196 | |||
197 | test('trusts a trusted certificate', () => { | ||
198 | const service = createTestService( | ||
199 | {}, | ||
200 | { | ||
201 | temporarilyTrustedCertificates: [testCertificate], | ||
202 | }, | ||
203 | ); | ||
204 | |||
205 | expect(service.isCertificateTemporarilyTrusted(testCertificate)).toBe(true); | ||
206 | }); | ||