Skip to content

Commit 9060bcc

Browse files
committed
test: unit tests for tauri credentials totp store apis
1 parent 41e5fbf commit 9060bcc

File tree

1 file changed

+139
-1
lines changed

1 file changed

+139
-1
lines changed

test/spec/Tauri-platform-test.js

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*
2020
*/
2121

22-
/*global describe, it, expect, beforeEach, afterEach, fs, path, Phoenix, jasmine*/
22+
/*global describe, it, expect, beforeEach, afterEach, fs, path, jasmine, expectAsync*/
2323

2424
define(function (require, exports, module) {
2525
if(!window.__TAURI__) {
@@ -135,5 +135,143 @@ define(function (require, exports, module) {
135135
}
136136
}, 120000);
137137
});
138+
139+
describe("Credentials OTP API Tests", function () {
140+
const scopeName = "testScope";
141+
const sessionID = "test-session-123";
142+
const otpSeed = "test-secret-seed";
143+
144+
beforeEach(async function () {
145+
// Cleanup before running tests
146+
await window.__TAURI__.invoke("delete_credential", { scopeName }).catch(() => {});
147+
});
148+
149+
afterEach(async function () {
150+
// Cleanup after tests
151+
await window.__TAURI__.invoke("delete_credential", { scopeName }).catch(() => {});
152+
});
153+
154+
describe("Credential Storage & OTP Generation", function () {
155+
it("Should store credentials successfully", async function () {
156+
await expectAsync(
157+
window.__TAURI__.invoke("store_credential", { scopeName, sessionId: sessionID, otpSeed })
158+
).toBeResolved();
159+
});
160+
161+
it("Should retrieve a valid OTP after storing credentials", async function () {
162+
await window.__TAURI__.invoke("store_credential", { scopeName, sessionId: sessionID, otpSeed });
163+
164+
const response = await window.__TAURI__.invoke("get_credential_otp", { scopeName });
165+
expect(response).toBeDefined();
166+
expect(response.session_id).toEqual(sessionID);
167+
expect(response.totp).toMatch(/^\d{6}$/); // OTP should be a 6-digit number
168+
});
169+
170+
it("Should retrieve a valid OTP after storing uuid as seed", async function () {
171+
const newSession = crypto.randomUUID();
172+
await window.__TAURI__.invoke("store_credential",
173+
{ scopeName, sessionId: newSession, otpSeed: crypto.randomUUID() });
174+
175+
const response = await window.__TAURI__.invoke("get_credential_otp", { scopeName });
176+
expect(response).toBeDefined();
177+
expect(response.session_id).toEqual(newSession);
178+
expect(response.totp).toMatch(/^\d{6}$/); // OTP should be a 6-digit number
179+
});
180+
181+
it("Should return an error if credentials do not exist", async function () {
182+
const response = await window.__TAURI__.invoke("get_credential_otp", { scopeName });
183+
expect(response).toEqual({ err_code: "NO_ENTRY" });
184+
});
185+
186+
it("Should delete stored credentials", async function () {
187+
await window.__TAURI__.invoke("store_credential", { scopeName, sessionId: sessionID, otpSeed });
188+
189+
// Ensure credential exists
190+
const responseBeforeDelete = await window.__TAURI__.invoke("get_credential_otp", { scopeName });
191+
expect(responseBeforeDelete.session_id).toEqual(sessionID);
192+
193+
// Delete credential
194+
await expectAsync(
195+
window.__TAURI__.invoke("delete_credential", { scopeName })
196+
).toBeResolved();
197+
198+
// Ensure credential is deleted
199+
const responseAfterDelete = await window.__TAURI__.invoke("get_credential_otp", { scopeName });
200+
expect(responseAfterDelete).toEqual({ err_code: "NO_ENTRY" });
201+
});
202+
203+
it("Should handle deletion of non-existent credentials gracefully", async function () {
204+
let error;
205+
try {
206+
await window.__TAURI__.invoke("delete_credential", { scopeName });
207+
} catch (err) {
208+
error = err;
209+
}
210+
211+
// The test should fail if no error was thrown
212+
expect(error).toBeDefined();
213+
214+
// Check for OS-specific error messages
215+
const expectedErrors = [
216+
"No matching entry found in secure storage", // Common error on Linux/macOS
217+
"The specified item could not be found in the keychain", // macOS Keychain
218+
"Element not found" // Windows Credential Manager
219+
];
220+
221+
const isExpectedError = expectedErrors.some(msg => error.includes(msg));
222+
expect(isExpectedError).toBeTrue();
223+
});
224+
225+
it("Should reject storing an empty seed", async function () {
226+
let error;
227+
try {
228+
await window.__TAURI__.invoke("store_credential",
229+
{ scopeName, sessionId: sessionID, otpSeed: "" });
230+
} catch (err) {
231+
error = err;
232+
}
233+
expect(error).toBeDefined();
234+
expect(error).toContain("SEED_TOO_SHORT");
235+
});
236+
237+
it("Should reject storing a seed that is too short", async function () {
238+
let error;
239+
try {
240+
await window.__TAURI__.invoke("store_credential",
241+
{ scopeName, sessionId: sessionID, otpSeed: "12345" });
242+
} catch (err) {
243+
error = err;
244+
}
245+
expect(error).toBeDefined();
246+
expect(error).toContain("SEED_TOO_SHORT");
247+
});
248+
249+
it("Should overwrite existing credentials when storing with the same scope", async function () {
250+
const oldSeed = crypto.randomUUID();
251+
await window.__TAURI__.invoke("store_credential",
252+
{ scopeName, sessionId: "old-session", otpSeed: oldSeed });
253+
254+
const responseBefore = await window.__TAURI__.invoke("get_credential_otp", { scopeName });
255+
expect(responseBefore.session_id).toEqual("old-session");
256+
257+
// Store new credentials with the same scope
258+
await window.__TAURI__.invoke("store_credential", { scopeName, sessionId: sessionID, otpSeed });
259+
260+
const responseAfter = await window.__TAURI__.invoke("get_credential_otp", { scopeName });
261+
expect(responseAfter.session_id).toEqual(sessionID);
262+
});
263+
264+
it("Should correctly encode and decode Base32 seed", async function () {
265+
const base32Seed = "JBSWY3DPEHPK3PXP"; // Valid Base32 seed
266+
await window.__TAURI__.invoke("store_credential",
267+
{ scopeName, sessionId: sessionID, otpSeed: base32Seed });
268+
269+
const response = await window.__TAURI__.invoke("get_credential_otp", { scopeName });
270+
expect(response).toBeDefined();
271+
expect(response.session_id).toEqual(sessionID);
272+
expect(response.totp).toMatch(/^\d{6}$/);
273+
});
274+
});
275+
});
138276
});
139277
});

0 commit comments

Comments
 (0)