Initial Commit
Some checks failed
Publish to Private NPM Registry / publish (push) Failing after 1m0s
Some checks failed
Publish to Private NPM Registry / publish (push) Failing after 1m0s
This commit is contained in:
commit
18cc482293
12 changed files with 4353 additions and 0 deletions
147
tests/FileKeystore.test.ts
Normal file
147
tests/FileKeystore.test.ts
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
import path from 'path';
|
||||
import NodeJose from 'node-jose';
|
||||
import { jest, describe, test, expect, beforeEach } from '@jest/globals';
|
||||
import type { FileKeystore } from '../src/FileKeystore.js'; // Import TYPE only (safe in ESM)
|
||||
|
||||
// We use unstable_mockModule because standard jest.mock struggles to intercept
|
||||
// core Node modules (like fs) in strict ESM mode.
|
||||
jest.unstable_mockModule('fs', () => ({
|
||||
// We must mock the 'default' export because your code uses: import fs from 'fs'
|
||||
default: {
|
||||
existsSync: jest.fn(),
|
||||
mkdirSync: jest.fn(),
|
||||
writeFileSync: jest.fn(),
|
||||
readFileSync: jest.fn(),
|
||||
},
|
||||
// We also mock named exports purely for safety, though 'default' is the key one here
|
||||
existsSync: jest.fn(),
|
||||
mkdirSync: jest.fn(),
|
||||
writeFileSync: jest.fn(),
|
||||
readFileSync: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock dependency
|
||||
jest.unstable_mockModule('@BridgemanAccessible/ba-auth/keystore', () => ({
|
||||
BaseKeystore: class {},
|
||||
Keystore: {
|
||||
addKeystoreType: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('FileKeystore', () => {
|
||||
// Variables to hold our dynamically imported modules
|
||||
let FileKeystoreClass: typeof FileKeystore;
|
||||
let mockFs: any;
|
||||
|
||||
const TEST_DIR = '.test-cert';
|
||||
const TEST_FILE = 'test-keystore.json';
|
||||
const FULL_PATH = path.join(TEST_DIR, TEST_FILE);
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
// 3. DYNAMICALLY IMPORT THE MODULES
|
||||
// This is the magic. We import AFTER the mock is defined.
|
||||
// This ensures 'fs' inside FileKeystore.ts is actually our mock.
|
||||
const fsModule = await import('fs');
|
||||
mockFs = fsModule.default; // Access the default export we mocked above
|
||||
|
||||
// Import your class under test
|
||||
// Note: You might need to add '.js' to the path if your resolving is strict
|
||||
const module = await import('../src/FileKeystore.js');
|
||||
FileKeystoreClass = module.FileKeystore;
|
||||
});
|
||||
|
||||
test('should create a NEW keystore if the file does not exist', async () => {
|
||||
// SETUP:
|
||||
// 1. Pretend the file does NOT exist
|
||||
mockFs.existsSync.mockReturnValue(false);
|
||||
// 2. Mock writeFileSync to do nothing (just verify it was called)
|
||||
mockFs.writeFileSync.mockImplementation(() => {});
|
||||
// 3. Mock mkdirSync
|
||||
mockFs.mkdirSync.mockImplementation(() => undefined);
|
||||
|
||||
// EXECUTE
|
||||
const keystoreInstance = await FileKeystoreClass.create(TEST_FILE, TEST_DIR);
|
||||
|
||||
// VERIFY
|
||||
// 1. Verify it checked for file existence
|
||||
expect(mockFs.existsSync).toHaveBeenCalledWith(FULL_PATH);
|
||||
|
||||
// 2. Verify it checked for directory existence (and created it)
|
||||
expect(mockFs.mkdirSync).toHaveBeenCalledWith(TEST_DIR);
|
||||
|
||||
// 3. Verify it wrote the new keystore to disk
|
||||
// We expect the first argument to be the path, and the second to be a JSON string
|
||||
expect(mockFs.writeFileSync).toHaveBeenCalledWith(
|
||||
FULL_PATH,
|
||||
expect.stringContaining('"keys":') // Simple check to ensure it looks like JSON
|
||||
);
|
||||
|
||||
// 4. Verify the instance path is set correctly
|
||||
expect(keystoreInstance.getKeystoreFilePath()).toBe(FULL_PATH);
|
||||
|
||||
// 5. Verify internal keystore state (node-jose should have generated keys)
|
||||
// @ts-ignore - accessing public property 'keystore' which might be protected in your real usage,
|
||||
// but implied public in the provided snippet logic
|
||||
const keys = keystoreInstance.keystore.all();
|
||||
expect(keys.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
test('should LOAD an existing keystore if the file exists', async () => {
|
||||
// SETUP:
|
||||
// 1. Create a real temporary keystore using node-jose to mimic a file on disk
|
||||
const realKeystore = await NodeJose.JWK.createKeyStore().generate('RSA', 2048);
|
||||
const keystoreJson = JSON.stringify(realKeystore.keystore.toJSON(true));
|
||||
|
||||
// 2. Pretend the file DOES exist
|
||||
mockFs.existsSync.mockReturnValue(true);
|
||||
|
||||
// 3. Pretend readFileSync returns our JSON string
|
||||
mockFs.readFileSync.mockReturnValue(keystoreJson);
|
||||
|
||||
// EXECUTE
|
||||
const keystoreInstance = await FileKeystoreClass.create(TEST_FILE, TEST_DIR);
|
||||
|
||||
// VERIFY
|
||||
// 1. It should check existence
|
||||
expect(mockFs.existsSync).toHaveBeenCalledWith(FULL_PATH);
|
||||
|
||||
// 2. It should READ the file
|
||||
expect(mockFs.readFileSync).toHaveBeenCalledWith(FULL_PATH, 'utf-8');
|
||||
|
||||
// 3. CRITICAL: It should NOT overwrite the file
|
||||
expect(mockFs.writeFileSync).not.toHaveBeenCalled();
|
||||
|
||||
// 4. CRITICAL: It should NOT try to create the directory again
|
||||
// (The code checks !existsSync(file), so it goes into the else block)
|
||||
expect(mockFs.mkdirSync).not.toHaveBeenCalled();
|
||||
|
||||
// 5. Verify the loaded keys match what we "mocked" on disk
|
||||
// @ts-ignore
|
||||
const loadedKeys = keystoreInstance.keystore.all();
|
||||
expect(loadedKeys.length).toBe(1);
|
||||
});
|
||||
|
||||
test('should create directory only if it is missing', async () => {
|
||||
// Scenario: File missing, Directory also missing
|
||||
mockFs.existsSync
|
||||
.mockReturnValueOnce(false) // First check: File exists? No.
|
||||
.mockReturnValueOnce(false); // Second check: Dir exists? No.
|
||||
|
||||
await FileKeystoreClass.create(TEST_FILE, TEST_DIR);
|
||||
|
||||
expect(mockFs.mkdirSync).toHaveBeenCalledWith(TEST_DIR);
|
||||
});
|
||||
|
||||
test('should NOT create directory if it already exists', async () => {
|
||||
// Scenario: File missing, Directory exists
|
||||
mockFs.existsSync
|
||||
.mockReturnValueOnce(false) // First check: File exists? No.
|
||||
.mockReturnValueOnce(true); // Second check: Dir exists? Yes.
|
||||
|
||||
await FileKeystoreClass.create(TEST_FILE, TEST_DIR);
|
||||
|
||||
expect(mockFs.mkdirSync).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue