Skip to content

Commit

Permalink
Added HistoryProvider interface
Browse files Browse the repository at this point in the history
  • Loading branch information
viktor-podzigun committed Nov 18, 2024
1 parent f26d54a commit 18acc64
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/history/HistoryProvider.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { useContext } from "react";

/**
* @typedef {{
* readonly name: string;
* readonly maxItemsCount: number;
* }} HistoryKind
*/

/**
* @typedef {{
* readonly item: string;
* readonly params?: object;
* }} History
*/

/**
* @typedef {{
* getAll(): Promise<History[]>;
* getOne(item: string): Promise<History | undefined>;
* save(h: History): Promise<void>;
* }} HistoryService
*/

/**
* @typedef {{
* get(kind: HistoryKind): Promise<HistoryService>;
* }} HistoryProvider
*/

const HistoryProvider = {};

HistoryProvider.Context = React.createContext(
/** @type {HistoryProvider | null} */ (null)
);

HistoryProvider.useHistoryProvider = () => {
const ctx = useContext(HistoryProvider.Context);
if (!ctx) {
throw Error(
"HistoryProvider.Context is not found." +
"\nPlease, make sure you use HistoryProvider.Context.Provider in parent component."
);
}
return ctx;
};

export default HistoryProvider;
2 changes: 2 additions & 0 deletions test/all.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ await import("./api/MockFileListApi.test.mjs");
await import("./api/MockFileSource.test.mjs");
await import("./api/MockFileTarget.test.mjs");

await import("./history/HistoryProvider.test.mjs");

await import("./sort/FileListSort.test.mjs");
75 changes: 75 additions & 0 deletions test/history/HistoryProvider.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import assert from "node:assert/strict";
import mockFunction from "mock-fn";
import { assertComponents, TestErrorBoundary } from "react-assert";
import HistoryProvider from "../../src/history/HistoryProvider.mjs";

const h = React.createElement;

const { describe, it } = await (async () => {
// @ts-ignore
const module = process.isBun ? "bun:test" : "node:test";
// @ts-ignore
return process.isBun // @ts-ignore
? Promise.resolve({ describe: (_, fn) => fn(), it: test })
: import(module);
})();

describe("HistoryProvider.test.mjs", () => {
it("should fail if no HistoryProvider.Context when useHistoryProvider", () => {
//given
// suppress intended error
// see: https://github.com/facebook/react/issues/11098#issuecomment-412682721
const savedConsoleError = console.error;
const consoleErrorMock = mockFunction(() => {
console.error = savedConsoleError;
});
console.error = consoleErrorMock;

const TestComp = () => {
HistoryProvider.useHistoryProvider();
return null;
};
const comp = h(TestComp, null, h(React.Fragment));

//when
const result = TestRenderer.create(h(TestErrorBoundary, null, comp)).root;

//then
assert.deepEqual(consoleErrorMock.times, 1);
assert.deepEqual(console.error, savedConsoleError);
assertComponents(
result.children,
h(
"div",
null,
"Error: HistoryProvider.Context is not found." +
"\nPlease, make sure you use HistoryProvider.Context.Provider in parent component."
)
);
});

it("should return HistoryProvider when useHistoryProvider", () => {
//given
const HistoryProviderMock = /** @type {HistoryProvider} */ ({});
let capturedProvider = null;
const TestComp = () => {
capturedProvider = HistoryProvider.useHistoryProvider();
return null;
};

//when
const result = TestRenderer.create(
h(
HistoryProvider.Context.Provider,
{ value: HistoryProviderMock },
h(TestComp, null)
)
).root;

//then
assert.deepEqual(result.type, TestComp);
assert.deepEqual(capturedProvider === HistoryProviderMock, true);
});
});
22 changes: 22 additions & 0 deletions types/history/HistoryProvider.d.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export default HistoryProvider;
export type HistoryKind = {
readonly name: string;
readonly maxItemsCount: number;
};
export type History = {
readonly item: string;
readonly params?: object;
};
export type HistoryService = {
getAll(): Promise<History[]>;
getOne(item: string): Promise<History | undefined>;
save(h: History): Promise<void>;
};
export type HistoryProvider = {
get(kind: HistoryKind): Promise<HistoryService>;
};
declare namespace HistoryProvider {
const Context: React.Context<HistoryProvider | null>;
function useHistoryProvider(): HistoryProvider;
}
import React from "react";

0 comments on commit 18acc64

Please sign in to comment.