Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/WJSoftware/wjfe-n-savant"
"url": "git+https://github.com/WJSoftware/wjfe-n-savant.git"
},
"license": "MIT",
"bugs": {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/Logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { logger, resetLogger, setLogger } from "./Logger.js";
import type { ILogger } from "$lib/types.js";

describe("logger", () => {
test("Should default to offLogger (not console)", () => {
test("Should default to offLogger when the library hasn't been initialized.", () => {
expect(logger).not.toBe(globalThis.console);
expect(logger.debug).toBeDefined();
expect(logger.log).toBeDefined();
Expand Down
88 changes: 14 additions & 74 deletions src/lib/core/options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import { resetRoutingOptions, routingOptions } from "./options.js";
describe("options", () => {
test("The routing options' initial values are the expected ones.", () => {
// Assert.
expect(routingOptions).toEqual({ full: false, hashMode: 'single', implicitMode: 'path' });
});

test("Should have correct default value for full option.", () => {
expect(routingOptions.full).toBe(false);
expect(routingOptions).toEqual({ hashMode: 'single', implicitMode: 'path' });
});

test("Should have correct default value for hashMode option.", () => {
Expand All @@ -19,20 +15,11 @@ describe("options", () => {
expect(routingOptions.implicitMode).toBe('path');
});

test("Should allow modification of full option.", () => {
const originalValue = routingOptions.full;
routingOptions.full = true;
expect(routingOptions.full).toBe(true);

// Restore original value
routingOptions.full = originalValue;
});

test("Should allow modification of hashMode option.", () => {
const originalValue = routingOptions.hashMode;
routingOptions.hashMode = 'multi';
expect(routingOptions.hashMode).toBe('multi');

// Restore original value
routingOptions.hashMode = originalValue;
});
Expand All @@ -41,77 +28,30 @@ describe("options", () => {
const originalValue = routingOptions.implicitMode;
routingOptions.implicitMode = 'hash';
expect(routingOptions.implicitMode).toBe('hash');

// Restore original value
routingOptions.implicitMode = originalValue;
});

test("Should maintain object reference integrity after modifications.", () => {
const optionsRef = routingOptions;
routingOptions.full = !routingOptions.full;

expect(optionsRef).toBe(routingOptions);
expect(optionsRef.full).toBe(routingOptions.full);

// Restore original value
routingOptions.full = false;
routingOptions.implicitMode = originalValue;
});

test("Should contain all required properties as non-nullable.", () => {
expect(routingOptions.full).toBeDefined();
expect(routingOptions.hashMode).toBeDefined();
expect(routingOptions.implicitMode).toBeDefined();

expect(typeof routingOptions.full).toBe('boolean');
expect(typeof routingOptions.hashMode).toBe('string');
expect(typeof routingOptions.implicitMode).toBe('string');
});

test("Should validate hashMode enum values.", () => {
const originalValue = routingOptions.hashMode;

// Valid values
routingOptions.hashMode = 'single';
expect(routingOptions.hashMode).toBe('single');

routingOptions.hashMode = 'multi';
expect(routingOptions.hashMode).toBe('multi');

// Restore original value
routingOptions.hashMode = originalValue;
});
describe('resetRoutingOptions', () => {
test("Should reset all options to defaults when resetRoutingOptions is called.", () => {
// Arrange.
const original = structuredClone(routingOptions);
routingOptions.hashMode = 'multi';
routingOptions.implicitMode = 'hash';

test("Should validate implicitMode enum values.", () => {
const originalValue = routingOptions.implicitMode;

// Valid values
routingOptions.implicitMode = 'hash';
expect(routingOptions.implicitMode).toBe('hash');

routingOptions.implicitMode = 'path';
expect(routingOptions.implicitMode).toBe('path');

// Restore original value
routingOptions.implicitMode = originalValue;
});

test("Should reset all options to defaults when resetRoutingOptions is called.", () => {
// Arrange - Modify all options to non-default values
routingOptions.full = true;
routingOptions.hashMode = 'multi';
routingOptions.implicitMode = 'hash';

// Verify they were changed
expect(routingOptions.full).toBe(true);
expect(routingOptions.hashMode).toBe('multi');
expect(routingOptions.implicitMode).toBe('hash');

// Act
resetRoutingOptions();
// Act.
resetRoutingOptions();

// Assert - Verify all options are back to defaults
expect(routingOptions.full).toBe(false);
expect(routingOptions.hashMode).toBe('single');
expect(routingOptions.implicitMode).toBe('path');
// Assert.
expect(routingOptions).deep.equal(original);
});
});
});
51 changes: 2 additions & 49 deletions src/lib/core/options.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,11 @@
/**
* Library's routing options.
*/
export type RoutingOptions = {
/**
* Whether to initialize the routing library with all features.
* @default false
*/
full?: boolean;
/**
* Whether to use a single or multiple hash mode. In single hash mode, the hash value is always one path; in multi
* mode, the hash value can be multiple paths.
*
* The multiple paths option shapes the hash value as: `'#id1=/path/of/id1;id2=/path/of/id2;...'`.
*
* @default 'single'
*/
hashMode?: 'single' | 'multi';
/**
* Mode routers operate when their `hash` property is not set (left `undefined`).
*
* In short: It tells the library what type of routing is assumed when no `hash` property is specified in `Router`,
* `Route`, `Fallback`, `Link`, or `RouterTrace` components.
*
* When set to `'path'`, create components for hash routing by setting the `hash` property to `true` or a string
* identifier; when set to `'hash'`, create components for path routing by setting the `hash` property to `false`.
*
* @default 'path'
*
* @example
* ```svelte
* // In main.ts:
* init({ implicitMode: 'hash' });
*
* // In App.svelte:
* <Router>
* <Route path="/path1">
* <View1 />
* </Route>
* </Router>
* ```
*
* Even though the `hash` property is not set in the `Router` or `Route` components, the library will treat both
* as hash-routing components because the `implicitMode` option was set to `'hash'`.
*/
implicitMode?: 'hash' | 'path';
}
import type { RoutingOptions } from "$lib/types.js";

/**
* Default routing options used for rollback.
*/
const defaultRoutingOptions: Required<RoutingOptions> = {
full: false,
hashMode: 'single',
implicitMode: 'path'
implicitMode: 'path',
};

/**
Expand Down
14 changes: 1 addition & 13 deletions src/lib/core/trace.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
import type { TraceOptions } from "$lib/types.js";
import type { RouterEngine } from "./RouterEngine.svelte.js";

/**
* Library's tracing options.
*/
export type TraceOptions = {
/**
* Whether to trace the router hierarchy.
*
* This consumes extra RAM and a bit more CPU cycles. Disable it on production builds.
* @default false
*/
routerHierarchy?: boolean;
};

/**
* Weak references to all router engines that are created.
*/
Expand Down
25 changes: 10 additions & 15 deletions src/lib/core/trace.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import { getAllChildRouters, resetTraceOptions, setTraceOptions, traceOptions } from "./trace.svelte.js";
import { getAllChildRouters, registerRouter, resetTraceOptions, setTraceOptions, traceOptions } from "./trace.svelte.js";
import { RouterEngine } from "./RouterEngine.svelte.js";
import { init } from "$lib/index.js";

const hoistedVars = vi.hoisted(() => ({
registerRouter: vi.fn(),
}));
vi.mock('./trace.svelte.js', async (originalImport) => {
const origModule = await originalImport() as any;
vi.mock(import('./trace.svelte.js'), async (importActual) => {
const actual = await importActual<typeof import("./trace.svelte.js")>();
return {
...origModule,
registerRouter: (...args: any[]) => {
hoistedVars.registerRouter.apply(null, args);
return origModule.registerRouter.apply(null, args);
}
}
...actual,
registerRouter: vi.fn(actual.registerRouter)
};
});

describe('setTraceOptions', () => {
test.each([
true,
Expand Down Expand Up @@ -64,14 +59,14 @@ describe('registerRouter', () => {
cleanup();
});
beforeEach(() => {
hoistedVars.registerRouter.mockClear();
vi.resetAllMocks();
});
test("Should be called when a new router engine is created.", () => {
// Act.
new RouterEngine();

// Assert.
expect(hoistedVars.registerRouter).toHaveBeenCalled();
expect(registerRouter).toHaveBeenCalled();
});
});

Expand All @@ -84,7 +79,7 @@ describe('getAllChildRouters', () => {
cleanup();
});
beforeEach(() => {
hoistedVars.registerRouter.mockClear();
vi.clearAllMocks();
});
test("Should return the children of the specified router.", () => {
// Arrange.
Expand Down
Loading