UNPKG

@daml/react

Version:

React framework to interact with a Daml ledger

828 lines • 40.8 kB
"use strict"; // Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. // SPDX-License-Identifier: Apache-2.0 var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); // NOTE(MH): Unfortunately the `act` function triggers this warning by looking // like a promise without being one. /* eslint-disable @typescript-eslint/no-floating-promises */ var react_1 = __importStar(require("react")); var react_hooks_1 = require("@testing-library/react-hooks"); var index_1 = __importStar(require("./index")); var events_1 = require("events"); var mockConstructor = jest.fn(); var mockQuery = jest.fn(); var mockFetch = jest.fn(); var mockFetchByKey = jest.fn(); var mockStreamQueries = jest.fn(); var mockStreamFetchByKeys = jest.fn(); var mockFunctions = [ mockConstructor, mockQuery, mockFetch, mockFetchByKey, mockStreamQueries, mockStreamFetchByKeys, ]; jest.mock("@daml/ledger", function () { return /** @class */ (function () { function class_1() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } mockConstructor.apply(void 0, args); } class_1.prototype.query = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return mockQuery.apply(void 0, args); }; class_1.prototype.fetch = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return mockFetch.apply(void 0, args); }; class_1.prototype.fetchByKey = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return mockFetchByKey.apply(void 0, args); }; class_1.prototype.streamQueries = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return mockStreamQueries.apply(void 0, args); }; class_1.prototype.streamFetchByKeys = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return mockStreamFetchByKeys.apply(void 0, args); }; return class_1; }()); }); /** * Returns a mock stream object using an `EventEmitter` to implement on, off functions. */ var mockStream = function () { var emitter = new events_1.EventEmitter(); var stream = { // eslint-disable-next-line @typescript-eslint/no-explicit-any on: function (type, listener) { return void emitter.on(type, listener); }, // eslint-disable-next-line @typescript-eslint/no-explicit-any off: function (type, listener) { return void emitter.on(type, listener); }, close: function () { emitter.removeAllListeners(); console.log("mock stream closed"); }, }; return [stream, emitter]; }; var TOKEN = "test_token"; var PARTY = "test_party"; var USER = { userId: "test_user" }; function renderDamlHook(callback) { var wrapper = function (_a) { var children = _a.children; return react_1.default.createElement(index_1.default, { token: TOKEN, party: PARTY, user: USER, reconnectThreshold: 1337 }, children); }; return (0, react_hooks_1.renderHook)(callback, { wrapper: wrapper }); } /** * Dummy template, needs at least the templateId field for debug messages emitted by * `useStreamQuery`. */ var Foo = { templateId: "FooTemplateId" }; beforeEach(function () { mockFunctions.forEach(function (mock) { return mock.mockClear(); }); }); test("DamlLedger", function () { renderDamlHook(function () { return; }); expect(mockConstructor).toHaveBeenCalledTimes(1); expect(mockConstructor).toHaveBeenLastCalledWith({ token: TOKEN, httpBaseUrl: undefined, wsBaseUrl: undefined, reconnectThreshold: 1337, }); }); test("useParty", function () { var result = renderDamlHook(function () { return (0, index_1.useParty)(); }).result; expect(result.current).toBe(PARTY); }); test("useUser", function () { var result = renderDamlHook(function () { return (0, index_1.useUser)(); }).result; expect(result.current).toBe(USER); }); describe("useQuery", function () { test("one shot without query", function () { return __awaiter(void 0, void 0, void 0, function () { var resolvent, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: resolvent = ["foo"]; mockQuery.mockReturnValueOnce(Promise.resolve(resolvent)); _a = renderDamlHook(function () { return (0, index_1.useQuery)(Foo); }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; expect(mockQuery).toHaveBeenCalledTimes(1); expect(mockQuery).toHaveBeenLastCalledWith(Foo, undefined); mockQuery.mockClear(); expect(result.current.contracts).toEqual([]); expect(result.current.loading).toBe(true); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(mockQuery).not.toHaveBeenCalled(); expect(result.current.contracts).toBe(resolvent); expect(result.current.loading).toBe(false); return [2 /*return*/]; } }); }); }); test("change to query", function () { return __awaiter(void 0, void 0, void 0, function () { var query1, query2, resolvent1, resolvent2, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: query1 = "foo-query"; query2 = "bar-query"; resolvent1 = ["foo"]; resolvent2 = ["bar"]; // First rendering works? mockQuery.mockReturnValueOnce(Promise.resolve(resolvent1)); _a = renderDamlHook(function () { var _a = (0, react_1.useState)(query1), query = _a[0], setQuery = _a[1]; var queryResult = (0, index_1.useQuery)(Foo, function () { return ({ query: query }); }, [query]); return { queryResult: queryResult, query: query, setQuery: setQuery }; }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; expect(mockQuery).toHaveBeenCalledTimes(1); expect(mockQuery).toHaveBeenLastCalledWith(Foo, { query: query1 }); mockQuery.mockClear(); expect(result.current.queryResult).toEqual({ contracts: [], loading: true, }); expect(result.current.query).toBe(query1); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(result.current.queryResult).toEqual({ contracts: resolvent1, loading: false, }); // Change to query triggers another call to JSON API? mockQuery.mockReturnValueOnce(Promise.resolve(resolvent2)); (0, react_hooks_1.act)(function () { return result.current.setQuery(query2); }); expect(mockQuery).toHaveBeenCalledTimes(1); expect(mockQuery).toHaveBeenLastCalledWith(Foo, { query: query2 }); mockQuery.mockClear(); expect(result.current.queryResult).toEqual({ contracts: [], loading: true, }); expect(result.current.query).toBe(query2); return [4 /*yield*/, waitForNextUpdate()]; case 2: _b.sent(); expect(result.current.queryResult).toEqual({ contracts: resolvent2, loading: false, }); return [2 /*return*/]; } }); }); }); test("rerendering without query change", function () { return __awaiter(void 0, void 0, void 0, function () { var query, resolvent, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: query = "query"; resolvent = ["foo"]; // First rendering works? mockQuery.mockReturnValueOnce(Promise.resolve(resolvent)); _a = renderDamlHook(function () { var setState = (0, react_1.useState)("state")[1]; var queryResult = (0, index_1.useQuery)(Foo, function () { return ({ query: query }); }, [query]); return { queryResult: queryResult, setState: setState }; }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; expect(mockQuery).toHaveBeenCalledTimes(1); mockQuery.mockClear(); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(result.current.queryResult).toEqual({ contracts: resolvent, loading: false, }); // Change to unrelated state does _not_ trigger another call to JSON API? (0, react_hooks_1.act)(function () { return result.current.setState("new-state"); }); expect(mockQuery).not.toHaveBeenCalled(); expect(result.current.queryResult).toEqual({ contracts: resolvent, loading: false, }); return [2 /*return*/]; } }); }); }); test("useReload", function () { return __awaiter(void 0, void 0, void 0, function () { var resolvent1, resolvent2, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: resolvent1 = ["foo"]; resolvent2 = ["bar"]; mockQuery.mockReturnValueOnce(Promise.resolve(resolvent1)); _a = renderDamlHook(function () { var reload = (0, index_1.useReload)(); var queryResult = (0, index_1.useQuery)(Foo); return { reload: reload, queryResult: queryResult }; }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; // first query expect(mockQuery).toHaveBeenCalledTimes(1); expect(mockQuery).toHaveBeenLastCalledWith(Foo, undefined); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(result.current.queryResult).toEqual({ contracts: resolvent1, loading: false, }); mockQuery.mockClear(); // query result changes mockQuery.mockReturnValueOnce(Promise.resolve(resolvent2)); // user reloads (0, react_hooks_1.act)(function () { return result.current.reload(); }); return [4 /*yield*/, waitForNextUpdate()]; case 2: _b.sent(); expect(mockQuery).toHaveBeenCalledTimes(1); expect(mockQuery).toHaveBeenLastCalledWith(Foo, undefined); expect(result.current.queryResult).toEqual({ contracts: resolvent2, loading: false, }); return [2 /*return*/]; } }); }); }); }); describe("useFetch", function () { test("one shot", function () { return __awaiter(void 0, void 0, void 0, function () { var contract, contractId, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: contract = { owner: "Alice" }; contractId = "1"; mockFetch.mockReturnValueOnce(Promise.resolve(contract)); _a = renderDamlHook(function () { return (0, index_1.useFetch)(Foo, contractId); }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; expect(mockFetch).toHaveBeenCalledTimes(1); expect(mockFetch).toHaveBeenLastCalledWith(Foo, contractId); mockFetch.mockClear(); expect(result.current).toEqual({ contract: null, loading: true }); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(mockFetch).not.toHaveBeenCalled(); expect(result.current).toEqual({ contract: contract, loading: false }); return [2 /*return*/]; } }); }); }); }); describe("useFetchByKey", function () { test("one shot", function () { return __awaiter(void 0, void 0, void 0, function () { var contract, key, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: contract = { owner: "Alice" }; key = contract.owner; mockFetchByKey.mockReturnValueOnce(Promise.resolve(contract)); _a = renderDamlHook(function () { return (0, index_1.useFetchByKey)(Foo, function () { return key; }, [key]); }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; expect(mockFetchByKey).toHaveBeenCalledTimes(1); expect(mockFetchByKey).toHaveBeenLastCalledWith(Foo, key); mockFetchByKey.mockClear(); expect(result.current).toEqual({ contract: null, loading: true }); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(mockFetchByKey).not.toHaveBeenCalled(); expect(result.current).toEqual({ contract: contract, loading: false }); return [2 /*return*/]; } }); }); }); test("change to key", function () { return __awaiter(void 0, void 0, void 0, function () { var contract1, key1, contract2, key2, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: contract1 = { owner: "Alice" }; key1 = contract1.owner; contract2 = { owner: "Bob" }; key2 = contract2.owner; // First rendering works? mockFetchByKey.mockReturnValueOnce(Promise.resolve(contract1)); _a = renderDamlHook(function () { var _a = (0, react_1.useState)(key1), key = _a[0], setKey = _a[1]; var queryResult = (0, index_1.useFetchByKey)(Foo, function () { return key; }, [key]); return { queryResult: queryResult, key: key, setKey: setKey }; }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; expect(mockFetchByKey).toHaveBeenCalledTimes(1); expect(mockFetchByKey).toHaveBeenLastCalledWith(Foo, key1); mockFetchByKey.mockClear(); expect(result.current.queryResult).toEqual({ contract: null, loading: true, }); expect(result.current.key).toBe(key1); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(result.current.queryResult).toEqual({ contract: contract1, loading: false, }); // Change to key triggers another call to JSON API? mockFetchByKey.mockReturnValueOnce(Promise.resolve(contract2)); (0, react_hooks_1.act)(function () { return result.current.setKey(key2); }); expect(mockFetchByKey).toHaveBeenCalledTimes(1); expect(mockFetchByKey).toHaveBeenLastCalledWith(Foo, key2); mockFetchByKey.mockClear(); expect(result.current.queryResult).toEqual({ contract: null, loading: true, }); expect(result.current.key).toBe(key2); return [4 /*yield*/, waitForNextUpdate()]; case 2: _b.sent(); expect(result.current.queryResult).toEqual({ contract: contract2, loading: false, }); return [2 /*return*/]; } }); }); }); test("rerendering without key change", function () { return __awaiter(void 0, void 0, void 0, function () { var contract, key, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: contract = { owner: "Alice" }; key = contract.owner; // First rendering works? mockFetchByKey.mockReturnValueOnce(Promise.resolve(contract)); _a = renderDamlHook(function () { var setState = (0, react_1.useState)("state")[1]; var queryResult = (0, index_1.useFetchByKey)(Foo, function () { return key; }, [key]); return { queryResult: queryResult, setState: setState }; }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; expect(mockFetchByKey).toHaveBeenCalledTimes(1); mockFetchByKey.mockClear(); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(result.current.queryResult).toEqual({ contract: contract, loading: false }); // Change to unrelated state does _not_ trigger another call to JSON API? (0, react_hooks_1.act)(function () { return result.current.setState("new-state"); }); expect(mockFetchByKey).not.toHaveBeenCalled(); expect(result.current.queryResult).toEqual({ contract: contract, loading: false }); return [2 /*return*/]; } }); }); }); test("useReload", function () { return __awaiter(void 0, void 0, void 0, function () { var contract1, key1, contract2, _a, result, waitForNextUpdate; return __generator(this, function (_b) { switch (_b.label) { case 0: contract1 = { owner: "Alice" }; key1 = contract1.owner; contract2 = { owner: "Bob" }; mockFetchByKey.mockReturnValueOnce(Promise.resolve(contract1)); _a = renderDamlHook(function () { var reload = (0, index_1.useReload)(); var fetchResult = (0, index_1.useFetchByKey)(Foo, function () { return key1; }, [key1]); return { reload: reload, fetchResult: fetchResult }; }), result = _a.result, waitForNextUpdate = _a.waitForNextUpdate; // first fetchByKey expect(mockFetchByKey).toHaveBeenCalledTimes(1); expect(mockFetchByKey).toHaveBeenLastCalledWith(Foo, key1); return [4 /*yield*/, waitForNextUpdate()]; case 1: _b.sent(); expect(result.current.fetchResult).toEqual({ contract: contract1, loading: false, }); mockFetchByKey.mockClear(); // fetchByKey result changes mockFetchByKey.mockReturnValueOnce(Promise.resolve(contract2)); // user reloads (0, react_hooks_1.act)(function () { return result.current.reload(); }); return [4 /*yield*/, waitForNextUpdate()]; case 2: _b.sent(); expect(mockFetchByKey).toHaveBeenCalledTimes(1); expect(mockFetchByKey).toHaveBeenLastCalledWith(Foo, key1); expect(result.current.fetchResult).toEqual({ contract: contract2, loading: false, }); return [2 /*return*/]; } }); }); }); }); /* * Note: LyingToTheCompiler should really be QueryResult here. However, that * maps to `{loading: boolean; contracts: CreateEvent<>[]}`, where each * `CreateEvent` has the contract data in a `payload` field. The existing tests * have been written against mocked streams returning `{loading: boolean; * contracts: payload[]}` directly, and I don't see much benefit in changing * that in the context of mocking all stream operations. */ function streamq(useFn, mkQuery) { return function () { test("live event changes loading status", function () { // setup var query = "foo-query"; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamQueries.mockReturnValueOnce(stream); var hookResult = renderDamlHook(function () { return useFn(Foo, mkQuery(query), [query]); }); expect(mockStreamQueries).toHaveBeenCalledTimes(1); expect(mockStreamQueries).toHaveBeenLastCalledWith(Foo, [{ query: query }]); // no events have been emitted. expect(hookResult.result.current).toEqual({ contracts: [], loading: true, }); // live event (0, react_hooks_1.act)(function () { return void emitter.emit("live", []); }); expect(hookResult.result.current).toEqual({ contracts: [], loading: false, }); }); test("live event changes loading status", function () { // setup var query = "foo-query"; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamQueries.mockReturnValueOnce(stream); var hookResult = renderDamlHook(function () { return useFn(Foo, mkQuery(query), [query]); }); expect(mockStreamQueries).toHaveBeenCalledTimes(1); expect(mockStreamQueries).toHaveBeenLastCalledWith(Foo, [{ query: query }]); // no events have been emitted. expect(hookResult.result.current).toEqual({ contracts: [], loading: true, }); // live event (0, react_hooks_1.act)(function () { return void emitter.emit("live", []); }); expect(hookResult.result.current).toEqual({ contracts: [], loading: false, }); }); test("closeHandler gets called", function () { // setup var query = "foo-query"; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamQueries.mockReturnValueOnce(stream); var closeHandler = jest.fn(); var hookResult = renderDamlHook(function () { return useFn(Foo, mkQuery(query), [query], closeHandler); }); expect(mockStreamQueries).toHaveBeenCalledTimes(1); expect(mockStreamQueries).toHaveBeenLastCalledWith(Foo, [{ query: query }]); // no events have been emitted. expect(hookResult.result.current).toEqual({ contracts: [], loading: true, }); expect(closeHandler).toHaveBeenCalledTimes(0); (0, react_hooks_1.act)(function () { return void emitter.emit("close", { code: 4000, reason: "" }); }); expect(closeHandler).toHaveBeenCalledTimes(1); expect(closeHandler).toHaveBeenLastCalledWith({ code: 4000, reason: "" }); }); test("empty stream", function () { // setup var query = "foo-query"; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamQueries.mockReturnValueOnce(stream); var hookResult = renderDamlHook(function () { return useFn(Foo, mkQuery(query), [query]); }); expect(mockStreamQueries).toHaveBeenCalledTimes(1); expect(mockStreamQueries).toHaveBeenLastCalledWith(Foo, [{ query: query }]); // live event (0, react_hooks_1.act)(function () { return void emitter.emit("live", []); }); // no events have been emitted. expect(hookResult.result.current).toEqual({ contracts: [], loading: false, }); // empty events (0, react_hooks_1.act)(function () { return void emitter.emit("change", []); }); expect(hookResult.result.current).toEqual({ contracts: [], loading: false, }); }); test("new events", function () { // setup var query = "foo-query"; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamQueries.mockReturnValueOnce(stream); var hookResult = renderDamlHook(function () { return useFn(Foo, mkQuery(query), [query]); }); expect(mockStreamQueries).toHaveBeenCalledTimes(1); expect(mockStreamQueries).toHaveBeenLastCalledWith(Foo, [ { query: query }, ]); expect(hookResult.result.current.contracts).toEqual([]); // live event (0, react_hooks_1.act)(function () { return void emitter.emit("live", []); }); expect(hookResult.result.current.loading).toBe(false); // one new event (0, react_hooks_1.act)(function () { return void emitter.emit("change", ["event1"]); }); expect(hookResult.result.current.contracts).toEqual(["event1"]); expect(hookResult.result.current.loading).toBe(false); // two new events replacing old one. (0, react_hooks_1.act)(function () { return void emitter.emit("change", ["event2", "event3"]); }); expect(hookResult.result.current).toEqual({ contracts: ["event2", "event3"], loading: false, }); }); test("changed query triggers reload", function () { // setup var query1 = "foo-query"; var query2 = "bar-query"; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamQueries.mockReturnValueOnce(stream); var result = renderDamlHook(function () { var _a = (0, react_1.useState)(query1), query = _a[0], setQuery = _a[1]; var queryResult = useFn(Foo, mkQuery(query), [query]); return { queryResult: queryResult, query: query, setQuery: setQuery }; }).result; expect(mockStreamQueries).toHaveBeenCalledTimes(1); expect(mockStreamQueries).toHaveBeenLastCalledWith(Foo, [ { query: query1 }, ]); // live event (0, react_hooks_1.act)(function () { return void emitter.emit("live", []); }); expect(result.current.queryResult).toEqual({ contracts: [], loading: false, }); // new events (0, react_hooks_1.act)(function () { return void emitter.emit("change", ["foo"]); }); expect(result.current.queryResult).toEqual({ contracts: ["foo"], loading: false, }); // change query, expect stream to have been called with new query. mockStreamQueries.mockClear(); mockStreamQueries.mockReturnValueOnce(stream); (0, react_hooks_1.act)(function () { return result.current.setQuery(query2); }); // live event (0, react_hooks_1.act)(function () { return void emitter.emit("live", null); }); // change event (0, react_hooks_1.act)(function () { return void emitter.emit("change", ["bar"]); }); expect(mockStreamQueries).toHaveBeenCalledTimes(1); expect(mockStreamQueries).toHaveBeenLastCalledWith(Foo, [ { query: query2 }, ]); expect(result.current.queryResult).toEqual({ contracts: ["bar"], loading: false, }); }); }; } describe("useStreamQuery", streamq(index_1.useStreamQuery, function (query) { return function () { return ({ query: query }); }; })); describe("useStreamQueries", streamq(index_1.useStreamQueries, function (query) { return function () { return [{ query: query }]; }; })); /* * Note: Ignored here should really be R. However, because all of the exiting * tests have been written to completely skip over CreateEvent and go straight * to payload (see `streamq` note), init and found need to be a different type * from Ignored. */ function streamk(useFn, mkQ, init, found) { return function () { test("empty stream", function () { var contract = { owner: "Alice" }; var key = contract.owner; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamFetchByKeys.mockReturnValueOnce(stream); var result = renderDamlHook(function () { return useFn(Foo, mkQ(key), [key]); }).result; expect(mockStreamFetchByKeys).toHaveBeenCalledTimes(1); expect(mockStreamFetchByKeys).toHaveBeenLastCalledWith(Foo, [key]); expect(result.current).toEqual(init); (0, react_hooks_1.act)(function () { return void emitter.emit("live"); }); expect(result.current).toEqual(__assign(__assign({}, init), { loading: false })); (0, react_hooks_1.act)(function () { return void emitter.emit("change", [null]); }); expect(result.current).toEqual(found(null)); }), test("new event", function () { var contract = { owner: "Alice" }; var key = contract.owner; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamFetchByKeys.mockReturnValueOnce(stream); var result = renderDamlHook(function () { return useFn(Foo, mkQ(key), [key]); }).result; expect(mockStreamFetchByKeys).toHaveBeenCalledTimes(1); expect(mockStreamFetchByKeys).toHaveBeenLastCalledWith(Foo, [key]); expect(result.current).toEqual(init); (0, react_hooks_1.act)(function () { return void emitter.emit("live"); }); expect(result.current).toEqual(__assign(__assign({}, init), { loading: false })); (0, react_hooks_1.act)(function () { return void emitter.emit("change", [contract]); }); expect(result.current).toEqual(found(contract)); }), test("changed key triggers reload", function () { var contract = { k1: "Alice", k2: "Bob" }; var key1 = contract.k1; var key2 = contract.k2; var _a = mockStream(), stream = _a[0], emitter = _a[1]; mockStreamFetchByKeys.mockReturnValueOnce(stream); var result = renderDamlHook(function () { var _a = (0, react_1.useState)(key1), key = _a[0], setKey = _a[1]; var fetchResult = useFn(Foo, mkQ(key), [key]); return { fetchResult: fetchResult, key: key, setKey: setKey }; }).result; (0, react_hooks_1.act)(function () { return void emitter.emit("live"); }); (0, react_hooks_1.act)(function () { return void emitter.emit("change", [contract]); }); expect(mockStreamFetchByKeys).toHaveBeenCalledTimes(1); expect(mockStreamFetchByKeys).toHaveBeenLastCalledWith(Foo, [key1]); expect(result.current.fetchResult).toEqual(found(contract)); mockStreamFetchByKeys.mockClear(); mockStreamFetchByKeys.mockReturnValueOnce(stream); (0, react_hooks_1.act)(function () { return result.current.setKey(key2); }); expect(mockStreamFetchByKeys).toHaveBeenCalledTimes(1); expect(mockStreamFetchByKeys).toHaveBeenLastCalledWith(Foo, [key2]); }); describe("createLedgerContext", function () { test("contexts can nest", function () { var innerLedger = (0, index_1.createLedgerContext)(); var innerTOKEN = "inner_TOKEN"; var innerPARTY = "inner_PARTY"; var innerUSER = { userId: "inner_USER" }; var outerLedger = (0, index_1.createLedgerContext)("Outer"); var outerTOKEN = "outer_TOKEN"; var outerPARTY = "outer_PARTY"; var outerUSER = { userId: "outer_USER" }; var innerWrapper = function (_a) { var children = _a.children; return react_1.default.createElement(innerLedger.DamlLedger, { token: innerTOKEN, party: innerPARTY, user: innerUSER }, children); }; var r1 = (0, react_hooks_1.renderHook)(function () { return innerLedger.useParty(); }, { wrapper: innerWrapper, }); expect(r1.result.current).toBe(innerPARTY); var outerWrapper = function (_a) { var children = _a.children; return react_1.default.createElement(outerLedger.DamlLedger, { token: outerTOKEN, party: outerPARTY, user: outerUSER }, innerWrapper({ children: children })); }; var r2 = (0, react_hooks_1.renderHook)(function () { return outerLedger.useParty(); }, { wrapper: outerWrapper, }); expect(r2.result.current).toBe(outerPARTY); var r3 = (0, react_hooks_1.renderHook)(function () { return innerLedger.useParty(); }, { wrapper: outerWrapper, }); expect(r3.result.current).toBe(innerPARTY); }); }); }; } describe("useStreamFetchByKey", streamk(index_1.useStreamFetchByKey, function (k) { return function () { return k; }; }, { loading: true, contract: null }, function (c) { return ({ loading: false, contract: c, }); })); describe("useStreamFetchByKeys", streamk(index_1.useStreamFetchByKeys, function (k) { return function () { return [k]; }; }, { loading: true, contracts: [] }, function (c) { return ({ loading: false, contracts: [c], }); })); //# sourceMappingURL=index.test.js.map