mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
## Summary Reorganizes the test directory structure for better clarity and maintainability: - **Rename `test/datahaven/` → `test/moonwall/`**: Clearly identifies these as Moonwall single-node tests - **Move `test/framework/` → `test/e2e/framework/`**: Groups e2e test utilities under a dedicated folder - **Move `test/suites/` → `test/e2e/suites/`**: Groups e2e test suites with the framework - **Add `test/e2e/framework/validators.ts`**: Extracts validator test helpers from utils into the e2e framework - **Update documentation**: README.md and E2E_FRAMEWORK_OVERVIEW.md reflect the new structure ### New Directory Structure ``` test/ ├── e2e/ │ ├── suites/ # E2E test suites (Kurtosis-based) │ └── framework/ # E2E test utilities & helpers ├── moonwall/ # Moonwall single-node tests ├── launcher/ # Network deployment tools └── ... ``` --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
176 lines
5.5 KiB
TypeScript
176 lines
5.5 KiB
TypeScript
import { type BlockCreationResponse, type DevModeContext, expect } from "@moonwall/cli";
|
|
import type {
|
|
ApiTypes,
|
|
AugmentedEvent,
|
|
AugmentedEvents,
|
|
SubmittableExtrinsic
|
|
} from "@polkadot/api/types";
|
|
import type { EventRecord } from "@polkadot/types/interfaces";
|
|
import type { IEvent } from "@polkadot/types/types";
|
|
|
|
export type ExtractTuple<P> = P extends AugmentedEvent<"rxjs", infer T> ? T : never;
|
|
|
|
export async function expectOk<
|
|
ApiType extends ApiTypes,
|
|
Call extends
|
|
| SubmittableExtrinsic<ApiType>
|
|
| Promise<SubmittableExtrinsic<ApiType>>
|
|
| string
|
|
| Promise<string>,
|
|
Calls extends Call | Call[],
|
|
BlockCreation extends BlockCreationResponse<
|
|
ApiType,
|
|
// @ts-expect-error TODO: fix this
|
|
Calls extends Call[] ? Awaited<Call>[] : Awaited<Call>
|
|
>
|
|
>(call: Promise<BlockCreation>): Promise<BlockCreation> {
|
|
const block = await call;
|
|
if (Array.isArray(block.result)) {
|
|
block.result.forEach((r, idx) => {
|
|
expect(
|
|
r.successful,
|
|
`tx[${idx}] - ${r.error?.name}${
|
|
r.extrinsic
|
|
? `\n\t\t${r.extrinsic.method.section}.${r.extrinsic.method.method}(${r.extrinsic.args
|
|
.map((d) => d.toHuman())
|
|
.join("; ")})`
|
|
: ""
|
|
}`
|
|
).to.be.true;
|
|
});
|
|
} else {
|
|
// @ts-expect-error TODO: fix this
|
|
expect(block.result!.successful, block.result!.error?.name).to.be.true;
|
|
}
|
|
return block;
|
|
}
|
|
|
|
export function expectSubstrateEvent<
|
|
ApiType extends ApiTypes,
|
|
Call extends
|
|
| SubmittableExtrinsic<ApiType>
|
|
| Promise<SubmittableExtrinsic<ApiType>>
|
|
| string
|
|
| Promise<string>,
|
|
Calls extends Call | Call[],
|
|
Event extends AugmentedEvents<ApiType>,
|
|
Section extends keyof Event,
|
|
Method extends keyof Event[Section],
|
|
Tuple extends ExtractTuple<Event[Section][Method]>
|
|
>(
|
|
//@ts-expect-error TODO: fix this
|
|
block: BlockCreationResponse<ApiType, Calls extends Call[] ? Awaited<Call>[] : Awaited<Call>>,
|
|
section: Section,
|
|
method: Method
|
|
): IEvent<Tuple> {
|
|
let event: EventRecord | undefined;
|
|
if (Array.isArray(block.result)) {
|
|
block.result.forEach((r) => {
|
|
const foundEvents = r.events.filter(
|
|
({ event }) => event.section.toString() === section && event.method.toString() === method
|
|
);
|
|
if (foundEvents.length > 0) {
|
|
expect(
|
|
event,
|
|
`Event ${section.toString()}.${method.toString()} appeared multiple times`
|
|
).toBeUndefined();
|
|
expect(
|
|
foundEvents,
|
|
`Event ${section.toString()}.${method.toString()} appeared multiple times`
|
|
).to.be.length(1);
|
|
event = foundEvents[0];
|
|
}
|
|
});
|
|
} else {
|
|
const foundEvents = (block.result! as any).events!.filter(
|
|
(item: any) =>
|
|
item.event.section.toString() === section && item.event.method.toString() === method
|
|
);
|
|
if (foundEvents.length > 0) {
|
|
expect(
|
|
foundEvents,
|
|
`Event ${section.toString()}.${method.toString()} appeared multiple times`
|
|
).to.be.length(1);
|
|
event = foundEvents[0];
|
|
}
|
|
}
|
|
expect(
|
|
event,
|
|
`Event ${section.toString()}.${method.toString()} not found:\n${(Array.isArray(block.result)
|
|
? block.result.flatMap((r) => r.events)
|
|
: block.result
|
|
? block.result.events
|
|
: []
|
|
)
|
|
.map(({ event }) => ` - ${event.section.toString()}.${event.method.toString()}\n`)
|
|
.join("")}`
|
|
).to.not.be.undefined;
|
|
return event!.event as any;
|
|
}
|
|
|
|
export function expectSubstrateEvents<
|
|
ApiType extends ApiTypes,
|
|
Call extends
|
|
| SubmittableExtrinsic<ApiType>
|
|
| Promise<SubmittableExtrinsic<ApiType>>
|
|
| string
|
|
| Promise<string>,
|
|
Calls extends Call | Call[],
|
|
Event extends AugmentedEvents<ApiType>,
|
|
Section extends keyof Event,
|
|
Method extends keyof Event[Section],
|
|
Tuple extends ExtractTuple<Event[Section][Method]>
|
|
>(
|
|
//@ts-expect-error TODO: fix this
|
|
block: BlockCreationResponse<ApiType, Calls extends Call[] ? Awaited<Call>[] : Awaited<Call>>,
|
|
section: Section,
|
|
method: Method
|
|
): IEvent<Tuple>[] {
|
|
const events: EventRecord[] = [];
|
|
if (Array.isArray(block.result)) {
|
|
block.result.forEach((r) => {
|
|
const foundEvents = r.events.filter(
|
|
({ event }) => event.section.toString() === section && event.method.toString() === method
|
|
);
|
|
if (foundEvents.length > 0) {
|
|
events.push(...foundEvents);
|
|
}
|
|
});
|
|
} else {
|
|
const foundEvents = (block.result! as any).events.filter(
|
|
(item: any) =>
|
|
item.event.section.toString() === section && item.event.method.toString() === method
|
|
);
|
|
if (foundEvents.length > 0) {
|
|
events.push(...foundEvents);
|
|
}
|
|
}
|
|
expect(events.length > 0).to.not.be.null;
|
|
return events.map(({ event }) => event) as any;
|
|
}
|
|
|
|
export async function expectSystemEvent(
|
|
blockHash: string,
|
|
section: string,
|
|
method: string,
|
|
context: DevModeContext
|
|
): Promise<EventRecord> {
|
|
const events = await getAllBlockEvents(blockHash, context);
|
|
const foundEvents = events.filter(
|
|
({ event }) => event.section.toString() === section && event.method.toString() === method
|
|
);
|
|
const event = foundEvents[0];
|
|
expect(
|
|
foundEvents,
|
|
`Event ${section.toString()}.${method.toString()} appeared multiple times`
|
|
).to.be.length(1);
|
|
expect(event, `Event ${section.toString()}.${method.toString()} not found in block ${blockHash}`)
|
|
.to.not.be.undefined;
|
|
return event;
|
|
}
|
|
|
|
async function getAllBlockEvents(hash: string, context: DevModeContext): Promise<EventRecord[]> {
|
|
const apiAt = await context.polkadotJs().at(hash);
|
|
const events = await apiAt.query.system.events();
|
|
return events;
|
|
}
|