Learning > presentation > Testing Edit this page Testing Although the presentation framework itself is thoroughly tested, consumers should still verify they get expected results for their iModel + ruleset combinations. The @bentley/presentation-testing package is delivered purely for that reason. The package delivers an API that allows creating hierarchies for supplied iModels and rulesets. Consumers can then verify the result using tools of their liking. Our recommendation is to use snapshot testing for 2 reasons: resulting hierarchies get rather large - testing the them in code might be difficult snapshots protect against regressions Example An example of setting up snapshot tests with the @bentley/presentation-testing package: describe("RulesetTesting", () => { let imodel: IModelConnection; const imodelPath = "assets/datasets/Properties_60InstancesWithUrl2.ibim"; before(async () => { // initialize presentation-testing await initialize(); }); after(async () => { // terminate presentation-testing await terminate(); }); beforeEach(async () => { // set up for testing imodel presentation data imodel = await SnapshotConnection.openFile(imodelPath); }); afterEach(async () => { await imodel.close(); }); it("generates correct hierarchy", async () => { const ruleset: Ruleset = { id: "test", rules: [{ ruleType: RuleTypes.RootNodes, autoExpand: true, specifications: [{ specType: ChildNodeSpecificationTypes.InstanceNodesOfSpecificClasses, classes: [{ schemaName: "BisCore", classNames: ["Subject"], }], instanceFilter: "this.Parent = NULL", arePolymorphic: false, groupByClass: false, groupByLabel: false, }], }, { ruleType: RuleTypes.ChildNodes, condition: "ParentNode.IsOfClass(\"Subject\", \"BisCore\")", onlyIfNotHandled: true, specifications: [{ specType: ChildNodeSpecificationTypes.RelatedInstanceNodes, relationshipPaths: [{ relationship: { schemaName: "BisCore", className: "SubjectOwnsSubjects", }, direction: RelationshipDirection.Forward, }], groupByClass: false, groupByLabel: false, }, { specType: ChildNodeSpecificationTypes.InstanceNodesOfSpecificClasses, classes: { schemaName: "BisCore", classNames: ["Model"], }, arePolymorphic: true, relatedInstances: [{ relationshipPath: { relationship: { schemaName: "BisCore", className: "ModelModelsElement", }, direction: RelationshipDirection.Forward, targetClass: { schemaName: "BisCore", className: "InformationPartitionElement", }, }, alias: "partition", isRequired: true, }], instanceFilter: "partition.Parent.Id = parent.ECInstanceId AND NOT this.IsPrivate", groupByClass: false, groupByLabel: false, }], }, { ruleType: RuleTypes.ChildNodes, condition: "ParentNode.IsOfClass(\"Model\", \"BisCore\")", onlyIfNotHandled: true, specifications: [{ specType: ChildNodeSpecificationTypes.RelatedInstanceNodes, relationshipPaths: [{ relationship: { schemaName: "BisCore", className: "ModelContainsElements", }, direction: RelationshipDirection.Forward, }], instanceFilter: "this.Parent = NULL", groupByClass: false, groupByLabel: false, }], }, { ruleType: RuleTypes.ChildNodes, condition: "ParentNode.IsOfClass(\"Element\", \"BisCore\")", onlyIfNotHandled: true, specifications: [{ specType: ChildNodeSpecificationTypes.RelatedInstanceNodes, relationshipPaths: [{ relationship: { schemaName: "BisCore", className: "ElementOwnsChildElements", }, direction: RelationshipDirection.Forward, }], groupByClass: false, groupByLabel: false, }], }], }; const builder = new HierarchyBuilder({ imodel }); // generate the hierarchy using a ruleset id const hierarchy = await builder.createHierarchy(ruleset); // verify through snapshot expect(hierarchy).to.matchSnapshot(); }); // VSTS#156270 // eslint-disable-next-line prefer-arrow/prefer-arrow-functions it.skip("generates correct content", async function () { const ruleset: Ruleset = { id: "test", rules: [{ ruleType: RuleTypes.Content, specifications: [{ specType: ContentSpecificationTypes.SelectedNodeInstances, }], }], }; const builder = new ContentBuilder({ imodel }); // generate content using ruleset id const instances = await builder.createContentForInstancePerClass(ruleset); // verify through snapshot // we loop through each instance and create a separate snapshot file // because snapshot engine has difficulties parsing big files for (const instance of instances) { // not providing filename and snapshot name to the 'matchSnapshot', because it seems // to ignore them when ChaiJestSnapshot.setFilename and setTestName is used configureSnapshotLocation(this.test!, "ruleset-testing-content-snaps", instance); expect(instance.records).to.matchSnapshot(); } }); }); Things to keep in mind Run initialize() before and terminate() after the tests Don't forget to close the iModel connection Ruleset can be provided either as an ID of already registered ruleset or as a Ruleset object. The object can even be imported from a JSON file: await builder.createHierarchy(require("rulesets/YourRuleset")) Last Updated: 11 June, 2024