Skip to content

Commit 50c7351

Browse files
committed
Version 2.0.7
* Added test coverage reporting
1 parent 4231ff1 commit 50c7351

32 files changed

+392
-462
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ npm i @puremvc/puremvc-typescript-multicore-framework
2424
* [React Native](https://en.wikipedia.org/wiki/React_Native)
2525

2626
## Status
27-
Production - [Version 2.0.6](https://github.com/PureMVC/puremvc-typescript-multicore-framework/blob/master/VERSION)
27+
Production - [Version 2.0.7](https://github.com/PureMVC/puremvc-typescript-multicore-framework/blob/master/VERSION)
2828

2929
## License
3030
* PureMVC MultiCore Framework for TypeScript - Copyright © 2025 [Saad Shams](https://www.linkedin.com/in/muizz)

VERSION

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Release Date: 2/27/25
44
Platform: TypeScript
55
Version: 2
66
Revision: 0
7-
Minor: 6
7+
Minor: 7
88
Authors: Saad Shams <[email protected]>
99
--------------------------------------------------------------------------
1010
2.0.0 - Brand new implementation of ported code, equivalent to AS3 MultiCore Version 1.0.5.
@@ -15,3 +15,4 @@ Release Date: 2/27/25
1515
and Mediator (viewComponent type any, not Object)
1616
2.0.5 - Fix package.json for importing types properly
1717
2.0.6 - Add test coverage reporting
18+
2.0.7 - Increase test coverage

docs/classes/Controller.html

+14-14
Large diffs are not rendered by default.

docs/classes/Facade.html

+29-29
Large diffs are not rendered by default.

docs/classes/MacroCommand.html

+10-10
Large diffs are not rendered by default.

docs/classes/Mediator.html

+17-17
Large diffs are not rendered by default.

docs/classes/Model.html

+13-13
Large diffs are not rendered by default.

docs/classes/Notification.html

+8-8
Large diffs are not rendered by default.

docs/classes/Notifier.html

+6-6
Large diffs are not rendered by default.

docs/classes/Observer.html

+8-8
Large diffs are not rendered by default.

docs/classes/Proxy.html

+15-15
Large diffs are not rendered by default.

docs/classes/SimpleCommand.html

+7-7
Large diffs are not rendered by default.

docs/classes/View.html

+16-16
Large diffs are not rendered by default.

docs/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<li><a href="https://en.wikipedia.org/wiki/React_(JavaScript_library)" target="_blank" class="external">React</a></li>
2020
<li><a href="https://en.wikipedia.org/wiki/React_Native" target="_blank" class="external">React Native</a></li>
2121
</ul>
22-
<a id="md:status" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Status<a href="#md:status" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Production - <a href="https://github.com/PureMVC/puremvc-typescript-multicore-framework/blob/master/VERSION" target="_blank" class="external">Version 2.0.5</a></p>
22+
<a id="md:status" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Status<a href="#md:status" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Production - <a href="https://github.com/PureMVC/puremvc-typescript-multicore-framework/blob/master/VERSION" target="_blank" class="external">Version 2.0.7</a></p>
2323
<a id="md:license" class="tsd-anchor"></a><h2 class="tsd-anchor-link">License<a href="#md:license" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><ul>
2424
<li>
2525
<p>PureMVC MultiCore Framework for TypeScript - Copyright © 2025 <a href="https://www.linkedin.com/in/muizz" target="_blank" class="external">Saad Shams</a></p>

docs/interfaces/ICommand.html

+4-4
Large diffs are not rendered by default.

docs/interfaces/IController.html

+5-5
Large diffs are not rendered by default.

docs/interfaces/IFacade.html

+15-15
Large diffs are not rendered by default.

docs/interfaces/IMediator.html

+9-9
Large diffs are not rendered by default.

docs/interfaces/IModel.html

+5-5
Large diffs are not rendered by default.

docs/interfaces/INotification.html

+5-5
Large diffs are not rendered by default.

docs/interfaces/INotifier.html

+3-3
Large diffs are not rendered by default.

docs/interfaces/IObserver.html

+5-5
Large diffs are not rendered by default.

docs/interfaces/IProxy.html

+7-7
Large diffs are not rendered by default.

docs/interfaces/IView.html

+8-8
Large diffs are not rendered by default.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@puremvc/puremvc-typescript-multicore-framework",
3-
"version": "2.0.6",
3+
"version": "2.0.7",
44
"description": "PureMVC MultiCore Framework for TypeScript",
55
"main": "./bin/cjs/index.js",
66
"module": "./bin/esm/index.js",

test/core/Controller.spec.ts

+26-12
Original file line numberDiff line numberDiff line change
@@ -126,35 +126,49 @@ describe("ControllerTest", () => {
126126
* test will fail.
127127
*/
128128
test("testReregisterAndExecuteCommand", () => {
129-
// Fetch the controller, register the ControllerTestCommand2 to handle 'ControllerTest2' notes
130129
const controller: IController = Controller.getInstance("ControllerTestKey5", (key: string) => new Controller(key));
131130
controller.registerCommand("ControllerTest2", () => new ControllerTestCommand2());
132131

133132
// Remove the Command from the Controller
134133
controller.removeCommand("ControllerTest2");
135134

136-
// Re-register the Command with the Controller
135+
// Re-register the Command, ensure it's only firing once per notification
137136
controller.registerCommand("ControllerTest2", () => new ControllerTestCommand2());
138137

139-
// Create a 'ControllerTest2' note
140138
const vo = new ControllerTestVO(12);
141139
const note = new Notification("ControllerTest2", vo);
142140

143-
// retrieve a reference to the View from the same core.
144-
const view = View.getInstance("ControllerTestKey5", (key: string) => new View((key)));
141+
const view = View.getInstance("ControllerTestKey5", (key: string) => new View(key));
145142

146-
// send the Notification
143+
// Sending notification; expecting the command to be executed starting at zero and multiplying input to 24
147144
view.notifyObservers(note);
148-
149-
// test assertions
150-
// if the command is executed once the value will be 24
151145
expect(vo.result).toBe(24);
152146

153-
// Prove that accumulation works in the VO by sending the notification again
147+
// Send the notification again; should now evaluate to 48
154148
view.notifyObservers(note);
155-
156-
// if the command is executed twice the value will be 48
157149
expect(vo.result).toBe(48);
158150
});
159151

152+
// Additional test case for constructing Controller with an existing key
153+
test("testConstructorWithExistingKey", () => {
154+
const key = "ControllerTestKeyExisting";
155+
const controller1: IController = Controller.getInstance(key, (key: string) => new Controller(key));
156+
expect(controller1).toBeDefined();
157+
expect(() => {
158+
new Controller(key);
159+
}).toThrow(Error("Controller instance for this Multiton key already constructed!"));
160+
});
161+
162+
// Test for removing a command twice
163+
test("testRemoveCommandTwice", () => {
164+
const controller: IController = Controller.getInstance("ControllerTestKeyTwice", k => new Controller(k));
165+
166+
controller.registerCommand("TestCommand", () => new ControllerTestCommand());
167+
168+
controller.removeCommand("TestCommand");
169+
170+
// Removing it again should not cause issues and should silently do nothing.
171+
controller.removeCommand("TestCommand");
172+
});
173+
160174
});

test/core/Model.spec.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe("ModelTest", () => {
3232
* Tests `registerProxy` and `retrieveProxy` in the same test.
3333
* These methods cannot currently be tested separately
3434
* in any meaningful way other than to show that the
35-
* methods do not throw exception when called.
35+
* methods do not throw exception when called.
3636
*/
3737
test("testRegisterAndRetrieveProxy", () => {
3838
// register a proxy and retrieve it.
@@ -116,4 +116,26 @@ describe("ModelTest", () => {
116116
expect(proxy.data).toBe(ModelTestProxy.ON_REMOVE_CALLED);
117117
});
118118

119+
// Test for constructor with an existing key
120+
test("testModelConstructorWithExistingKeyThrowsError", () => {
121+
const key = "ExistingModelKey";
122+
Model.getInstance(key, k => new Model(k));
123+
124+
expect(() => new Model(key)).toThrow("Model instance for this Multiton key already constructed!");
125+
});
126+
127+
// Test for removing a proxy twice
128+
test("testRemoveProxyTwice", () => {
129+
const model: IModel = Model.getInstance("ModelTestKeyTwice", k => new Model(k));
130+
131+
const proxy: IProxy = new Proxy("testProxy", {});
132+
model.registerProxy(proxy);
133+
134+
const removedProxy = model.removeProxy("testProxy");
135+
expect(removedProxy).toBe(proxy);
136+
137+
const secondRemovedProxy = model.removeProxy("testProxy");
138+
expect(secondRemovedProxy).toBeNull();
139+
});
140+
119141
});

test/core/View.spec.ts

+31
Original file line numberDiff line numberDiff line change
@@ -354,4 +354,35 @@ describe("ViewTest", () => {
354354
expect(obj.counter).toBe(0);
355355
});
356356

357+
// Test for removing a mediator twice
358+
test("testRemoveMediatorTwice", () => {
359+
// Get the Multiton View instance
360+
const view = View.getInstance("ViewTestKey12", (key: string) => new View(key));
361+
362+
// Create and register the test mediator
363+
const mediator: IMediator = new Mediator("testMediator", {});
364+
view.registerMediator(mediator);
365+
366+
// Remove the mediator
367+
const removedMediator = view.removeMediator("testMediator");
368+
369+
// Assert that the mediator is removed
370+
expect(removedMediator).toBe(mediator);
371+
372+
// Attempt to remove the mediator again and expect `null`
373+
const secondRemovedMediator = view.removeMediator("testMediator");
374+
expect(secondRemovedMediator).toBe(null);
375+
});
376+
377+
// Test for notifyObservers with no registrations
378+
test("testNotifyObserversWithNoRegistrations", () => {
379+
const view: IView = View.getInstance("ViewTestKeyNoObservers", (key: string) => new View(key));
380+
381+
const notification = new Notification("UnusedNotification");
382+
383+
// Call notifyObservers on a notification with no registered observers
384+
// Should not throw an error and should be handled gracefully
385+
expect(() => view.notifyObservers(notification)).not.toThrow();
386+
});
387+
357388
});

test/patterns/command/MacroCommand.spec.ts

+19-49
Original file line numberDiff line numberDiff line change
@@ -6,61 +6,31 @@
66
// Your reuse is governed by the BSD-3-Clause License
77
//
88

9-
import {Notification} from "../../../src";
10-
import {MacroCommandTestVO} from "./MacroCommandTestVO";
11-
import {MacroCommandTestCommand} from "./MacroCommandTestCommand";
9+
import { MacroCommand } from "../../../src/patterns/command/MacroCommand";
10+
import { Notification } from "../../../src/patterns/observer/Notification";
1211

1312
/**
14-
* Test the PureMVC SimpleCommand class.
13+
* Test the PureMVC MacroCommand class.
1514
*
16-
* @see MacroCommandTestVO
17-
* @see MacroCommandTestCommand
15+
* @see MacroCommand
1816
*/
1917
describe("MacroCommandTest", () => {
2018

21-
/**
22-
* Tests operation of a `MacroCommand`.
23-
*
24-
* This test creates a new `Notification`, adding a
25-
* `MacroCommandTestVO` as the body.
26-
* It then creates a `MacroCommandTestCommand` and invokes
27-
* its `execute` method, passing in the
28-
* `Notification`.
29-
*
30-
* The `MacroCommandTestCommand` has defined an
31-
* `initializeMacroCommand` method, which is
32-
* called automatically by its constructor. In this method
33-
* the `MacroCommandTestCommand` adds 2 SubCommands
34-
* to itself, `MacroCommandTestSub1Command` and
35-
* `MacroCommandTestSub2Command`.
36-
*
37-
* The `MacroCommandTestVO` has 2 result properties,
38-
* one is set by `MacroCommandTestSub1Command` by
39-
* multiplying the input property by 2, and the other is set
40-
* by `MacroCommandTestSub2Command` by multiplying
41-
* the input property by itself.
42-
*
43-
* Success is determined by evaluating the 2 result properties
44-
* on the `MacroCommandTestVO` that was passed to
45-
* the `MacroCommandTestCommand` on the Notification
46-
* body.
47-
*/
48-
test("testMacroCommandExecute", () => {
49-
// Create the VO
50-
const vo: MacroCommandTestVO = new MacroCommandTestVO(5);
51-
52-
// Create the Notification
53-
const notification = new Notification("MacroCommandTest", vo);
54-
55-
// Create the SimpleCommand
56-
const command: MacroCommandTestCommand = new MacroCommandTestCommand();
57-
58-
// Execute the SimpleCommand
59-
command.execute(notification);
60-
61-
// test assertions
62-
expect(vo.result1).toBe(10);
63-
expect(vo.result2).toBe(25);
19+
test("testExecuteWithUndefinedSubCommand", () => {
20+
class TestMacroCommand extends MacroCommand {
21+
public initializeMacroCommand(): void {
22+
this.addSubCommand(undefined as any); // intentionally adding undefined
23+
}
24+
}
25+
26+
const macroCommand = new TestMacroCommand();
27+
const notification = new Notification("TestNotification");
28+
29+
// Call execute and ensure it handles the undefined command gracefully
30+
expect(() => macroCommand.execute(notification)).not.toThrow();
31+
32+
// Since the subcommand was undefined, no ICommand should be executed, thus, nothing to assert on command effects
33+
// Additional assertions might include verifying that no state was changed
6434
});
6535

6636
});

0 commit comments

Comments
 (0)