Skip to content

Commit

Permalink
Merge pull request #304 from modelix/fix/vue-model-api-error-reference
Browse files Browse the repository at this point in the history
fix(vue-model-api): expose errors in references correctly
  • Loading branch information
odzhychko authored Oct 31, 2023
2 parents 8a60923 + 537aef0 commit 3f127c4
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 51 deletions.
14 changes: 14 additions & 0 deletions vue-model-api/src/useModelClient.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { watchEffect } from "vue";
import { useModelClient } from "./useModelClient";

test("test client connection error is exposed", (done) => {
const { error } = useModelClient("anURL", () => {
return Promise.reject("A connection error.");
});
watchEffect(() => {
if (error.value !== null) {
expect(error.value).toBe("A connection error.");
done();
}
});
});
10 changes: 7 additions & 3 deletions vue-model-api/src/useModelClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ type ClientJS = org.modelix.model.client2.ClientJS;
* Defaults to connecting directly to the modelix model server under the given URL.
*
* @returns {Object} values Wrapper around diffrent returned values.
* @returns {Ref<ClientJS>} values.client Reactive reference to a client.
* @returns {Ref<ClientJS | null>} values.client Reactive reference to a client.
* @returns {() => void} values.dispose A function to manually dispose the client.
* @returns {Ref<unknown>} values.error Reactive reference to a client connection error.
*/
export function useModelClient(
url: MaybeRefOrGetter<string>,
getClient: (url: string) => Promise<ClientJS> = connectClient,
) {
): {
client: Ref<ClientJS | null>;
dispose: () => void;
error: Ref<unknown>;
} {
let client: ClientJS | null = null;
const clientRef: Ref<ClientJS | null> = shallowRef(client);
const errorRef: Ref<unknown> = shallowRef(null);
Expand All @@ -52,7 +56,7 @@ export function useModelClient(
}
},
(reason, isResultOfLastStartedPromise) => {
if (!isResultOfLastStartedPromise) {
if (isResultOfLastStartedPromise) {
errorRef.value = reason;
}
},
Expand Down
96 changes: 51 additions & 45 deletions vue-model-api/src/useRootNode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,63 +9,69 @@ type ClientJS = org.modelix.model.client2.ClientJS;
type ChangeJS = org.modelix.model.client2.ChangeJS;
const { loadModelsFromJson } = org.modelix.model.client2;

const root = {
root: {},
};

function getClient(_url: string): Promise<ClientJS> {
return Promise.resolve(new TestClientJS() as unknown as ClientJS);
}
test("test branch connects", (done) => {
class SuccessfulBranchJS {
public rootNode: INodeJS;

class TestBranchJS implements BranchJS {
public disposed = false;
public rootNode: INodeJS;
constructor(branchId: string, changeCallback: (change: ChangeJS) => void) {
const root = {
root: {},
};

constructor(branchId: string, changeCallback: (change: ChangeJS) => void) {
this.rootNode = loadModelsFromJson([JSON.stringify(root)], changeCallback);
this.rootNode.setPropertyValue("branchId", branchId);
this.rootNode = loadModelsFromJson(
[JSON.stringify(root)],
changeCallback,
);
this.rootNode.setPropertyValue("branchId", branchId);
}
}

dispose(): void {
this.disposed = true;
class SuccessfulClientJS {
connectBranch(
_repositoryId: string,
branchId: string,
changeCallback: (change: ChangeJS) => void,
): Promise<BranchJS> {
return Promise.resolve(
new SuccessfulBranchJS(branchId, changeCallback) as BranchJS,
);
}
}

// @ts-ignore It is fine to be undefined, because we do not pass it back to Kotlin code.
__doNotUseOrImplementIt: undefined;
}
const { client } = useModelClient("anURL", () =>
Promise.resolve(new SuccessfulClientJS() as ClientJS),
);

class TestClientJS implements ClientJS {
public disposed = false;
const { rootNode } = useRootNode(client, "aRepository", "aBranch");

dispose(): void {
this.disposed = true;
}
connectBranch(
_repositoryId: string,
branchId: string,
changeCallback: (change: ChangeJS) => void,
): Promise<BranchJS> {
return Promise.resolve(
new TestBranchJS(branchId, changeCallback) as unknown as BranchJS,
);
}
fetchBranches(_repositoryId: string): Promise<string[]> {
throw new Error("Method not implemented.");
}
fetchRepositories(): Promise<string[]> {
throw new Error("Method not implemented.");
watchEffect(() => {
if (rootNode.value !== null) {
expect(rootNode.value.getPropertyValue("branchId")).toBe("aBranch");
done();
}
});
});

test("test branch connection error is exposed", (done) => {
class FailingClientJS {
connectBranch(
_repositoryId: string,
_branchId: string,
_changeCallback: (change: ChangeJS) => void,
): Promise<BranchJS> {
return Promise.reject("Could not connect branch.");
}
}

// @ts-ignore It is fine to be undefined, because we do not pass it back to Kotlin code.
__doNotUseOrImplementIt: undefined;
}
const { client } = useModelClient("anURL", () =>
Promise.resolve(new FailingClientJS() as ClientJS),
);

const { error } = useRootNode(client, "aRepository", "aBranch");

test("test branch connects", (done) => {
const { client } = useModelClient("anURL", getClient);
const { rootNode } = useRootNode(client, "aRepository", "aBranch");
watchEffect(() => {
if (rootNode.value !== null) {
expect(rootNode.value.getPropertyValue("branchId")).toBe("aBranch");
if (error.value !== null) {
expect(error.value).toBe("Could not connect branch.");
done();
}
});
Expand Down
10 changes: 7 additions & 3 deletions vue-model-api/src/useRootNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@ type ChangeJS = org.modelix.model.client2.ChangeJS;
* @param branchId - Reactive reference of a branchId in the repository of the model server.
*
* @returns {Object} values Wrapper around diffrent returned values.
* @returns {Ref<ClientJS>} values.rootNode Reactive reference to a reactive root node.
* @returns {Ref<INodeJS | null>} values.rootNode Reactive reference to a reactive root node.
* @returns {() => void} values.dispose A function to manually dispose the root node.
* @returns {Ref<unknown>} values.error Reactive reference to a connection error.
*/
export function useRootNode(
client: MaybeRefOrGetter<ClientJS | null>,
repositoryId: MaybeRefOrGetter<string | null>,
branchId: MaybeRefOrGetter<string | null>,
) {
): {
rootNode: Ref<INodeJS | null>;
dispose: () => void;
error: Ref<unknown>;
} {
let branch: BranchJS | null = null;
const rootNodeRef: Ref<INodeJS | null> = shallowRef(null);
const errorRef: Ref<unknown> = shallowRef(null);
Expand Down Expand Up @@ -83,7 +87,7 @@ export function useRootNode(
}
},
(reason, isResultOfLastStartedPromise) => {
if (!isResultOfLastStartedPromise) {
if (isResultOfLastStartedPromise) {
errorRef.value = reason;
}
},
Expand Down

0 comments on commit 3f127c4

Please sign in to comment.