mirror of
https://github.com/status-im/sourcecred.git
synced 2025-02-18 15:38:10 +00:00
credExplorer gets adapters from one point (#786)
Currently, the `credExplorer` uses the `defaultStaticAdapters`, but it imports these adapters in multiple places. If we decide to make the adapters configurable (e.g. when we start supporting more plugins) this will be a problem. This change modifies the cred explorer so that the adapters always come from a prop declaration on the app. Then the adapters are passed into the `state` module's functional entry points, rather than letting `state` depend on the default adapters directly. This change is motivated by the fact that my WeightConfig cleanup can be done more cleanly if the adapters are present as a prop on the App. Test plan: Unit tests are updated. Also, `git grep defaultStaticAdapters` reaveals that the adapters are only consumed once.
This commit is contained in:
parent
f7383bbc90
commit
d77c76082d
@ -9,7 +9,6 @@ import CheckedLocalStore from "../checkedLocalStore";
|
|||||||
import BrowserLocalStore from "../browserLocalStore";
|
import BrowserLocalStore from "../browserLocalStore";
|
||||||
|
|
||||||
import {type EdgeEvaluator} from "../../core/attribution/pagerank";
|
import {type EdgeEvaluator} from "../../core/attribution/pagerank";
|
||||||
import {defaultStaticAdapters} from "../adapters/defaultPlugins";
|
|
||||||
import {PagerankTable} from "./pagerankTable/Table";
|
import {PagerankTable} from "./pagerankTable/Table";
|
||||||
import {WeightConfig} from "./WeightConfig";
|
import {WeightConfig} from "./WeightConfig";
|
||||||
import RepositorySelect from "./RepositorySelect";
|
import RepositorySelect from "./RepositorySelect";
|
||||||
@ -20,6 +19,8 @@ import {
|
|||||||
type StateTransitionMachineInterface,
|
type StateTransitionMachineInterface,
|
||||||
uninitializedState,
|
uninitializedState,
|
||||||
} from "./state";
|
} from "./state";
|
||||||
|
import {StaticAdapterSet} from "../adapters/adapterSet";
|
||||||
|
import {defaultStaticAdapters} from "../adapters/defaultPlugins";
|
||||||
|
|
||||||
export default class AppPage extends React.Component<{|+assets: Assets|}> {
|
export default class AppPage extends React.Component<{|+assets: Assets|}> {
|
||||||
static _LOCAL_STORE = new CheckedLocalStore(
|
static _LOCAL_STORE = new CheckedLocalStore(
|
||||||
@ -31,11 +32,21 @@ export default class AppPage extends React.Component<{|+assets: Assets|}> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const App = createApp(createStateTransitionMachine);
|
const App = createApp(createStateTransitionMachine);
|
||||||
return <App assets={this.props.assets} localStore={AppPage._LOCAL_STORE} />;
|
return (
|
||||||
|
<App
|
||||||
|
assets={this.props.assets}
|
||||||
|
adapters={defaultStaticAdapters()}
|
||||||
|
localStore={AppPage._LOCAL_STORE}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = {|+assets: Assets, +localStore: LocalStore|};
|
type Props = {|
|
||||||
|
+assets: Assets,
|
||||||
|
+localStore: LocalStore,
|
||||||
|
+adapters: StaticAdapterSet,
|
||||||
|
|};
|
||||||
type State = {|
|
type State = {|
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
edgeEvaluator: ?EdgeEvaluator,
|
edgeEvaluator: ?EdgeEvaluator,
|
||||||
@ -110,6 +121,7 @@ export function createApp(
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
this.stateTransitionMachine.loadGraphAndRunPagerank(
|
this.stateTransitionMachine.loadGraphAndRunPagerank(
|
||||||
this.props.assets,
|
this.props.assets,
|
||||||
|
this.props.adapters,
|
||||||
NullUtil.get(this.state.edgeEvaluator),
|
NullUtil.get(this.state.edgeEvaluator),
|
||||||
GithubPrefix.user
|
GithubPrefix.user
|
||||||
)
|
)
|
||||||
@ -119,7 +131,7 @@ export function createApp(
|
|||||||
</button>
|
</button>
|
||||||
<WeightConfig
|
<WeightConfig
|
||||||
onChange={(edgeEvaluator) => this.setState({edgeEvaluator})}
|
onChange={(edgeEvaluator) => this.setState({edgeEvaluator})}
|
||||||
adapters={defaultStaticAdapters()}
|
adapters={this.props.adapters}
|
||||||
/>
|
/>
|
||||||
<LoadingIndicator appState={this.state.appState} />
|
<LoadingIndicator appState={this.state.appState} />
|
||||||
{pagerankTable}
|
{pagerankTable}
|
||||||
|
@ -38,7 +38,11 @@ describe("app/credExplorer/App", () => {
|
|||||||
}
|
}
|
||||||
const App = createApp(createMockSTM);
|
const App = createApp(createMockSTM);
|
||||||
const el = shallow(
|
const el = shallow(
|
||||||
<App assets={new Assets("/foo/")} localStore={localStore} />
|
<App
|
||||||
|
assets={new Assets("/foo/")}
|
||||||
|
adapters={new StaticAdapterSet([])}
|
||||||
|
localStore={localStore}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
if (setState == null || getState == null) {
|
if (setState == null || getState == null) {
|
||||||
throw new Error("Initialization problems");
|
throw new Error("Initialization problems");
|
||||||
@ -156,6 +160,7 @@ describe("app/credExplorer/App", () => {
|
|||||||
expect(loadGraphAndRunPagerank).toBeCalledTimes(1);
|
expect(loadGraphAndRunPagerank).toBeCalledTimes(1);
|
||||||
expect(loadGraphAndRunPagerank).toBeCalledWith(
|
expect(loadGraphAndRunPagerank).toBeCalledWith(
|
||||||
el.instance().props.assets,
|
el.instance().props.assets,
|
||||||
|
el.instance().props.adapters,
|
||||||
edgeEvaluator,
|
edgeEvaluator,
|
||||||
GithubPrefix.user
|
GithubPrefix.user
|
||||||
);
|
);
|
||||||
|
@ -12,9 +12,7 @@ import {
|
|||||||
pagerank,
|
pagerank,
|
||||||
} from "../../core/attribution/pagerank";
|
} from "../../core/attribution/pagerank";
|
||||||
|
|
||||||
import {DynamicAdapterSet} from "../adapters/adapterSet";
|
import {StaticAdapterSet, DynamicAdapterSet} from "../adapters/adapterSet";
|
||||||
|
|
||||||
import {defaultStaticAdapters} from "../adapters/defaultPlugins";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This models the UI states of the credExplorer/App as a state machine.
|
This models the UI states of the credExplorer/App as a state machine.
|
||||||
@ -72,10 +70,11 @@ export function uninitializedState(): AppState {
|
|||||||
// Exported for testing purposes.
|
// Exported for testing purposes.
|
||||||
export interface StateTransitionMachineInterface {
|
export interface StateTransitionMachineInterface {
|
||||||
+setRepo: (Repo) => void;
|
+setRepo: (Repo) => void;
|
||||||
+loadGraph: (Assets) => Promise<boolean>;
|
+loadGraph: (Assets, StaticAdapterSet) => Promise<boolean>;
|
||||||
+runPagerank: (EdgeEvaluator, NodeAddressT) => Promise<void>;
|
+runPagerank: (EdgeEvaluator, NodeAddressT) => Promise<void>;
|
||||||
+loadGraphAndRunPagerank: (
|
+loadGraphAndRunPagerank: (
|
||||||
Assets,
|
Assets,
|
||||||
|
StaticAdapterSet,
|
||||||
EdgeEvaluator,
|
EdgeEvaluator,
|
||||||
NodeAddressT
|
NodeAddressT
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
@ -89,6 +88,7 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||||||
setState: (AppState) => void;
|
setState: (AppState) => void;
|
||||||
loadGraphWithAdapters: (
|
loadGraphWithAdapters: (
|
||||||
assets: Assets,
|
assets: Assets,
|
||||||
|
adapters: StaticAdapterSet,
|
||||||
repo: Repo
|
repo: Repo
|
||||||
) => Promise<GraphWithAdapters>;
|
) => Promise<GraphWithAdapters>;
|
||||||
pagerank: (
|
pagerank: (
|
||||||
@ -102,6 +102,7 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||||||
setState: (AppState) => void,
|
setState: (AppState) => void,
|
||||||
loadGraphWithAdapters: (
|
loadGraphWithAdapters: (
|
||||||
assets: Assets,
|
assets: Assets,
|
||||||
|
adapters: StaticAdapterSet,
|
||||||
repo: Repo
|
repo: Repo
|
||||||
) => Promise<GraphWithAdapters>,
|
) => Promise<GraphWithAdapters>,
|
||||||
pagerank: (
|
pagerank: (
|
||||||
@ -126,7 +127,10 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Loads the graph, reports whether it was successful */
|
/** Loads the graph, reports whether it was successful */
|
||||||
async loadGraph(assets: Assets): Promise<boolean> {
|
async loadGraph(
|
||||||
|
assets: Assets,
|
||||||
|
adapters: StaticAdapterSet
|
||||||
|
): Promise<boolean> {
|
||||||
const state = this.getState();
|
const state = this.getState();
|
||||||
if (state.type !== "READY_TO_LOAD_GRAPH") {
|
if (state.type !== "READY_TO_LOAD_GRAPH") {
|
||||||
throw new Error("Tried to loadGraph in incorrect state");
|
throw new Error("Tried to loadGraph in incorrect state");
|
||||||
@ -137,7 +141,11 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||||||
let newState: ?AppState;
|
let newState: ?AppState;
|
||||||
let success = true;
|
let success = true;
|
||||||
try {
|
try {
|
||||||
const graphWithAdapters = await this.loadGraphWithAdapters(assets, repo);
|
const graphWithAdapters = await this.loadGraphWithAdapters(
|
||||||
|
assets,
|
||||||
|
adapters,
|
||||||
|
repo
|
||||||
|
);
|
||||||
newState = {
|
newState = {
|
||||||
type: "READY_TO_RUN_PAGERANK",
|
type: "READY_TO_RUN_PAGERANK",
|
||||||
graphWithAdapters,
|
graphWithAdapters,
|
||||||
@ -206,6 +214,7 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||||||
|
|
||||||
async loadGraphAndRunPagerank(
|
async loadGraphAndRunPagerank(
|
||||||
assets: Assets,
|
assets: Assets,
|
||||||
|
adapters: StaticAdapterSet,
|
||||||
edgeEvaluator: EdgeEvaluator,
|
edgeEvaluator: EdgeEvaluator,
|
||||||
totalScoreNodePrefix: NodeAddressT
|
totalScoreNodePrefix: NodeAddressT
|
||||||
) {
|
) {
|
||||||
@ -216,7 +225,7 @@ export class StateTransitionMachine implements StateTransitionMachineInterface {
|
|||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "READY_TO_LOAD_GRAPH":
|
case "READY_TO_LOAD_GRAPH":
|
||||||
const loadedGraph = await this.loadGraph(assets);
|
const loadedGraph = await this.loadGraph(assets, adapters);
|
||||||
if (loadedGraph) {
|
if (loadedGraph) {
|
||||||
await this.runPagerank(edgeEvaluator, totalScoreNodePrefix);
|
await this.runPagerank(edgeEvaluator, totalScoreNodePrefix);
|
||||||
}
|
}
|
||||||
@ -237,8 +246,9 @@ export type GraphWithAdapters = {|
|
|||||||
|};
|
|};
|
||||||
export async function loadGraphWithAdapters(
|
export async function loadGraphWithAdapters(
|
||||||
assets: Assets,
|
assets: Assets,
|
||||||
|
adapters: StaticAdapterSet,
|
||||||
repo: Repo
|
repo: Repo
|
||||||
): Promise<GraphWithAdapters> {
|
): Promise<GraphWithAdapters> {
|
||||||
const adapters = await defaultStaticAdapters().load(assets, repo);
|
const dynamicAdapters = await adapters.load(assets, repo);
|
||||||
return {graph: adapters.graph(), adapters};
|
return {graph: dynamicAdapters.graph(), adapters: dynamicAdapters};
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ describe("app/credExplorer/state", () => {
|
|||||||
};
|
};
|
||||||
const loadGraphMock: (
|
const loadGraphMock: (
|
||||||
assets: Assets,
|
assets: Assets,
|
||||||
|
adapters: StaticAdapterSet,
|
||||||
repo: Repo
|
repo: Repo
|
||||||
) => Promise<GraphWithAdapters> = jest.fn();
|
) => Promise<GraphWithAdapters> = jest.fn();
|
||||||
const pagerankMock: (
|
const pagerankMock: (
|
||||||
@ -136,25 +137,28 @@ describe("app/credExplorer/state", () => {
|
|||||||
];
|
];
|
||||||
for (const b of badStates) {
|
for (const b of badStates) {
|
||||||
const {stm} = example(b);
|
const {stm} = example(b);
|
||||||
await expect(stm.loadGraph(new Assets("/my/gateway/"))).rejects.toThrow(
|
await expect(
|
||||||
"incorrect state"
|
stm.loadGraph(new Assets("/my/gateway/"), new StaticAdapterSet([]))
|
||||||
);
|
).rejects.toThrow("incorrect state");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it("passes along the adapters and repo", () => {
|
it("passes along the adapters and repo", () => {
|
||||||
const {stm, loadGraphMock} = example(readyToLoadGraph());
|
const {stm, loadGraphMock} = example(readyToLoadGraph());
|
||||||
expect(loadGraphMock).toHaveBeenCalledTimes(0);
|
expect(loadGraphMock).toHaveBeenCalledTimes(0);
|
||||||
const assets = new Assets("/my/gateway/");
|
const assets = new Assets("/my/gateway/");
|
||||||
stm.loadGraph(assets);
|
const adapters = new StaticAdapterSet([]);
|
||||||
|
stm.loadGraph(assets, adapters);
|
||||||
expect(loadGraphMock).toHaveBeenCalledTimes(1);
|
expect(loadGraphMock).toHaveBeenCalledTimes(1);
|
||||||
expect(loadGraphMock.mock.calls[0]).toHaveLength(2);
|
expect(loadGraphMock).toHaveBeenCalledWith(
|
||||||
expect(loadGraphMock.mock.calls[0][0]).toBe(assets);
|
assets,
|
||||||
expect(loadGraphMock.mock.calls[0][1]).toEqual(makeRepo("foo", "bar"));
|
adapters,
|
||||||
|
makeRepo("foo", "bar")
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it("immediately sets loading status", () => {
|
it("immediately sets loading status", () => {
|
||||||
const {getState, stm} = example(readyToLoadGraph());
|
const {getState, stm} = example(readyToLoadGraph());
|
||||||
expect(loading(getState())).toBe("NOT_LOADING");
|
expect(loading(getState())).toBe("NOT_LOADING");
|
||||||
stm.loadGraph(new Assets("/my/gateway/"));
|
stm.loadGraph(new Assets("/my/gateway/"), new StaticAdapterSet([]));
|
||||||
expect(loading(getState())).toBe("LOADING");
|
expect(loading(getState())).toBe("LOADING");
|
||||||
expect(getState().type).toBe("READY_TO_LOAD_GRAPH");
|
expect(getState().type).toBe("READY_TO_LOAD_GRAPH");
|
||||||
});
|
});
|
||||||
@ -162,7 +166,10 @@ describe("app/credExplorer/state", () => {
|
|||||||
const {getState, stm, loadGraphMock} = example(readyToLoadGraph());
|
const {getState, stm, loadGraphMock} = example(readyToLoadGraph());
|
||||||
const gwa = graphWithAdapters();
|
const gwa = graphWithAdapters();
|
||||||
loadGraphMock.mockResolvedValue(gwa);
|
loadGraphMock.mockResolvedValue(gwa);
|
||||||
const succeeded = await stm.loadGraph(new Assets("/my/gateway/"));
|
const succeeded = await stm.loadGraph(
|
||||||
|
new Assets("/my/gateway/"),
|
||||||
|
new StaticAdapterSet([])
|
||||||
|
);
|
||||||
expect(succeeded).toBe(true);
|
expect(succeeded).toBe(true);
|
||||||
const state = getState();
|
const state = getState();
|
||||||
expect(loading(state)).toBe("NOT_LOADING");
|
expect(loading(state)).toBe("NOT_LOADING");
|
||||||
@ -182,7 +189,10 @@ describe("app/credExplorer/state", () => {
|
|||||||
resolve(graphWithAdapters());
|
resolve(graphWithAdapters());
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const succeeded = await stm.loadGraph(new Assets("/my/gateway/"));
|
const succeeded = await stm.loadGraph(
|
||||||
|
new Assets("/my/gateway/"),
|
||||||
|
new StaticAdapterSet([])
|
||||||
|
);
|
||||||
expect(succeeded).toBe(false);
|
expect(succeeded).toBe(false);
|
||||||
const state = getState();
|
const state = getState();
|
||||||
expect(loading(state)).toBe("NOT_LOADING");
|
expect(loading(state)).toBe("NOT_LOADING");
|
||||||
@ -195,7 +205,10 @@ describe("app/credExplorer/state", () => {
|
|||||||
// $ExpectFlowError
|
// $ExpectFlowError
|
||||||
console.error = jest.fn();
|
console.error = jest.fn();
|
||||||
loadGraphMock.mockRejectedValue(error);
|
loadGraphMock.mockRejectedValue(error);
|
||||||
const succeeded = await stm.loadGraph(new Assets("/my/gateway/"));
|
const succeeded = await stm.loadGraph(
|
||||||
|
new Assets("/my/gateway/"),
|
||||||
|
new StaticAdapterSet([])
|
||||||
|
);
|
||||||
expect(succeeded).toBe(false);
|
expect(succeeded).toBe(false);
|
||||||
const state = getState();
|
const state = getState();
|
||||||
expect(loading(state)).toBe("FAILED");
|
expect(loading(state)).toBe("FAILED");
|
||||||
@ -282,6 +295,7 @@ describe("app/credExplorer/state", () => {
|
|||||||
await expect(
|
await expect(
|
||||||
stm.loadGraphAndRunPagerank(
|
stm.loadGraphAndRunPagerank(
|
||||||
new Assets("gateway"),
|
new Assets("gateway"),
|
||||||
|
new StaticAdapterSet([]),
|
||||||
edgeEvaluator(),
|
edgeEvaluator(),
|
||||||
NodeAddress.empty
|
NodeAddress.empty
|
||||||
)
|
)
|
||||||
@ -293,11 +307,12 @@ describe("app/credExplorer/state", () => {
|
|||||||
(stm: any).runPagerank = jest.fn();
|
(stm: any).runPagerank = jest.fn();
|
||||||
stm.loadGraph.mockResolvedValue(true);
|
stm.loadGraph.mockResolvedValue(true);
|
||||||
const assets = new Assets("/gateway/");
|
const assets = new Assets("/gateway/");
|
||||||
|
const adapters = new StaticAdapterSet([]);
|
||||||
const prefix = NodeAddress.fromParts(["bar"]);
|
const prefix = NodeAddress.fromParts(["bar"]);
|
||||||
const ee = edgeEvaluator();
|
const ee = edgeEvaluator();
|
||||||
await stm.loadGraphAndRunPagerank(assets, ee, prefix);
|
await stm.loadGraphAndRunPagerank(assets, adapters, ee, prefix);
|
||||||
expect(stm.loadGraph).toHaveBeenCalledTimes(1);
|
expect(stm.loadGraph).toHaveBeenCalledTimes(1);
|
||||||
expect(stm.loadGraph).toHaveBeenCalledWith(assets);
|
expect(stm.loadGraph).toHaveBeenCalledWith(assets, adapters);
|
||||||
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
|
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
|
||||||
expect(stm.runPagerank).toHaveBeenCalledWith(ee, prefix);
|
expect(stm.runPagerank).toHaveBeenCalledWith(ee, prefix);
|
||||||
});
|
});
|
||||||
@ -307,8 +322,14 @@ describe("app/credExplorer/state", () => {
|
|||||||
(stm: any).runPagerank = jest.fn();
|
(stm: any).runPagerank = jest.fn();
|
||||||
stm.loadGraph.mockResolvedValue(false);
|
stm.loadGraph.mockResolvedValue(false);
|
||||||
const assets = new Assets("/gateway/");
|
const assets = new Assets("/gateway/");
|
||||||
|
const adapters = new StaticAdapterSet([]);
|
||||||
const prefix = NodeAddress.fromParts(["bar"]);
|
const prefix = NodeAddress.fromParts(["bar"]);
|
||||||
await stm.loadGraphAndRunPagerank(assets, edgeEvaluator(), prefix);
|
await stm.loadGraphAndRunPagerank(
|
||||||
|
assets,
|
||||||
|
adapters,
|
||||||
|
edgeEvaluator(),
|
||||||
|
prefix
|
||||||
|
);
|
||||||
expect(stm.loadGraph).toHaveBeenCalledTimes(1);
|
expect(stm.loadGraph).toHaveBeenCalledTimes(1);
|
||||||
expect(stm.runPagerank).toHaveBeenCalledTimes(0);
|
expect(stm.runPagerank).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
@ -318,7 +339,12 @@ describe("app/credExplorer/state", () => {
|
|||||||
(stm: any).runPagerank = jest.fn();
|
(stm: any).runPagerank = jest.fn();
|
||||||
const prefix = NodeAddress.fromParts(["bar"]);
|
const prefix = NodeAddress.fromParts(["bar"]);
|
||||||
const ee = edgeEvaluator();
|
const ee = edgeEvaluator();
|
||||||
await stm.loadGraphAndRunPagerank(new Assets("/gateway/"), ee, prefix);
|
await stm.loadGraphAndRunPagerank(
|
||||||
|
new Assets("/gateway/"),
|
||||||
|
new StaticAdapterSet([]),
|
||||||
|
ee,
|
||||||
|
prefix
|
||||||
|
);
|
||||||
expect(stm.loadGraph).toHaveBeenCalledTimes(0);
|
expect(stm.loadGraph).toHaveBeenCalledTimes(0);
|
||||||
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
|
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
|
||||||
expect(stm.runPagerank).toHaveBeenCalledWith(ee, prefix);
|
expect(stm.runPagerank).toHaveBeenCalledWith(ee, prefix);
|
||||||
@ -329,7 +355,12 @@ describe("app/credExplorer/state", () => {
|
|||||||
(stm: any).runPagerank = jest.fn();
|
(stm: any).runPagerank = jest.fn();
|
||||||
const prefix = NodeAddress.fromParts(["bar"]);
|
const prefix = NodeAddress.fromParts(["bar"]);
|
||||||
const ee = edgeEvaluator();
|
const ee = edgeEvaluator();
|
||||||
await stm.loadGraphAndRunPagerank(new Assets("/gateway/"), ee, prefix);
|
await stm.loadGraphAndRunPagerank(
|
||||||
|
new Assets("/gateway/"),
|
||||||
|
new StaticAdapterSet([]),
|
||||||
|
ee,
|
||||||
|
prefix
|
||||||
|
);
|
||||||
expect(stm.loadGraph).toHaveBeenCalledTimes(0);
|
expect(stm.loadGraph).toHaveBeenCalledTimes(0);
|
||||||
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
|
expect(stm.runPagerank).toHaveBeenCalledTimes(1);
|
||||||
expect(stm.runPagerank).toHaveBeenCalledWith(ee, prefix);
|
expect(stm.runPagerank).toHaveBeenCalledWith(ee, prefix);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user