UNPKG

infusion

Version:

Infusion is an application framework for developing flexible stuff with JavaScript

749 lines (685 loc) 24.8 kB
/* Copyright The Infusion copyright holders See the AUTHORS.md file at the top-level directory of this distribution and at https://github.com/fluid-project/infusion/raw/main/AUTHORS.md. Licensed under the Educational Community License (ECL), Version 2.0 or the New BSD license. You may not use this file except in compliance with one these Licenses. You may obtain a copy of the ECL 2.0 License and BSD License at https://github.com/fluid-project/infusion/raw/main/Infusion-LICENSE.txt */ /* eslint strict: ["error", "global"] */ /* global jqUnit */ "use strict"; fluid.registerNamespace("fluid.tests"); /** Testing environment - holds both fixtures as well as components under test, exposes global test driver **/ fluid.defaults("fluid.tests.myTestTree", { gradeNames: ["fluid.test.testEnvironment"], components: { cat: { type: "fluid.tests.cat" }, catTester: { type: "fluid.tests.catTester" } } }); /** Component under test **/ fluid.defaults("fluid.tests.cat", { gradeNames: ["fluid.component"], invokers: { makeSound: "fluid.tests.cat.makeSound" } }); fluid.tests.cat.makeSound = function () { return "meow"; }; /** Test Case Holder - holds declarative representation of test cases **/ fluid.defaults("fluid.tests.catTester", { gradeNames: ["fluid.test.testCaseHolder"], invokers: { testMeow: "fluid.tests.globalCatTest" }, modules: [ /* declarative specification of tests */ { name: "Cat test case", tests: [{ expect: 1, name: "Test Meow", type: "test", func: "{that}.testMeow", args: "{cat}" }, { expect: 1, name: "Test Global Meow", type: "test", func: "fluid.tests.globalCatTest", args: "{cat}" }] }] }); fluid.tests.globalCatTest = function (catt) { jqUnit.assertEquals("Sound", "meow", catt.makeSound()); }; fluid.defaults("fluid.tests.dynamicCATT", { gradeNames: ["fluid.modelComponent"], catts: ["catt1", "catt2"], dynamicComponents: { catts: { sources: "{that}.options.catts", type: "fluid.tests.cat" } } }); fluid.defaults("fluid.tests.sourceTester", { gradeNames: ["fluid.test.testEnvironment"], components: { tree: { type: "fluid.tests.dynamicCATT" }, fixtures: { type: "fluid.test.testCaseHolder", options: { moduleSource: { funcName: "fluid.tests.cattModuleSource", args: "{sourceTester}.tree" } } } } }); fluid.tests.cattModuleSource = function (dynamic) { var sequence = []; fluid.visitComponentChildren(dynamic, function (child) { sequence.push({ name: "Test Meow " + (sequence.length + 1), type: "test", func: "fluid.tests.globalCatTest", args: child }); }, {}); return { name: "Dynamic module source tests", tests: { name: "Dynamic CATT tests", sequence: sequence } }; }; fluid.tests.cancelOrDie = function (that) { that.timer = setTimeout(function () { fluid.fail("Hang timer did not execute before 2000ms"); }, 2000); }; fluid.tests.cancelTimer = function (that) { jqUnit.assert("Successfully cancelled hang timer"); clearTimeout(that.timer); that.events.onUnhang.fire(); }; fluid.defaults("fluid.tests.hangTester", { // tests FLUID-5252 gradeNames: ["fluid.test.testEnvironment"], hangWait: 1000, // speed up the test run by detecting a hang after only 1000ms events: { onUnhang: null }, listeners: { onSequenceHang: { funcName: "fluid.tests.cancelTimer", args: "{that}" } }, components: { fixtures: { type: "fluid.test.testCaseHolder", options: { modules: [ { name: "Hang test case", tests: [{ name: "Hang test sequence", expect: 1, sequence: [{ funcName: "fluid.tests.cancelOrDie", args: "{testEnvironment}" }, { event: "{testEnvironment}.events.onUnhang" }] }] }] } } } }); fluid.tests.pushListenerReport = function (arg1, that) { that.listenerReport = [arg1]; }; fluid.tests.pushFixedListenerReport = function (that) { that.environment.listenerReport.push("Fixed argument"); }; fluid.defaults("fluid.tests.listenerArg", { // tests FLUID-5496 gradeNames: ["fluid.test.testEnvironment"], events: { onPush: null }, components: { fixtures: { type: "fluid.test.testCaseHolder", options: { modules: [ { name: "Listener arg tester", tests: [{ name: "Listener arg sequence", expect: 2, sequence: [{ func: "{testEnvironment}.events.onPush.fire", args: "{testEnvironment}" }, { event: "{testEnvironment}.events.onPush", listener: "fluid.tests.pushListenerReport", args: ["Direct argument", "{arguments}.0"] }, { func: "jqUnit.assertDeepEq", args: ["Reporter should have fired", ["Direct argument"], "{testEnvironment}.listenerReport"] }, { func: "{testEnvironment}.events.onPush.fire", args: "{testEnvironment}" }, { event: "{testEnvironment}.events.onPush", listener: "fluid.tests.pushFixedListenerReport", args: { environment: "{arguments}.0" // tests FLUID-5583 } }, { func: "jqUnit.assertDeepEq", args: ["Reporter should have fired", ["Direct argument", "Fixed argument"], "{testEnvironment}.listenerReport"] }] }] }] } } } }); // FLUID-5497 model listener priority fluid.tests.storeListenedValue = function (that, value) { that.listenedValue = value; }; fluid.tests.makePriorityChangeChecker = function (that, expectedCurrent, expectedListener) { return function () { jqUnit.assertEquals("Current value expected in model", expectedCurrent, that.model); jqUnit.assertEquals("Old value expected in component", expectedListener, that.listenedValue); }; }; fluid.defaults("fluid.tests.modelTestTree", { gradeNames: ["fluid.test.testEnvironment", "fluid.modelComponent"], model: 0, members: { listenedValue: 0 }, modelListeners: { "": { funcName: "fluid.tests.storeListenedValue", args: ["{that}", "{change}.value"], priority: 0 // Weak priority - note that larger numbers are serviced earlier } }, components: { testCases: { type: "fluid.tests.modelPriorityCases" } } }); fluid.defaults("fluid.tests.modelPriorityCases", { gradeNames: ["fluid.test.testCaseHolder"], modules: [ { name: "FLUID-5497 Model listener priority tests", tests: [{ name: "Model priority sequence", expect: 4, sequence: [ { func: "{modelTestTree}.applier.change", args: ["", 1] }, { listenerMaker: "fluid.tests.makePriorityChangeChecker", makerArgs: ["{modelTestTree}", 1, 0], // listener lags behind us spec: {path: "", priority: 10}, // higher priority than listener changeEvent: "{modelTestTree}.applier.modelChanged" }, { func: "{modelTestTree}.applier.change", args: ["", 2] }, { listenerMaker: "fluid.tests.makePriorityChangeChecker", makerArgs: ["{modelTestTree}", 2, 2], // listener is ahead of us spec: {path: "", priority: "last"}, changeEvent: "{modelTestTree}.applier.modelChanged" }] }] }] }); // FLUID-5559 double firing of onTestCaseStart // in presence of the bug, we will get two firings of onTestCaseStart and hence an extra onCreate of the component, // and hence one extra assertion fluid.defaults("fluid.tests.onTestCaseStart.tree", { gradeNames: ["fluid.test.testEnvironment"], components: { targetTree: { type: "fluid.component", options: { events: { "hearIt": null }, listeners: { "onCreate.hearIt": { listener: "{that}.events.hearIt.fire" } } }, createOnEvent: "{testCases}.events.onTestCaseStart" }, testCases: { type: "fluid.test.testCaseHolder" } } }); fluid.defaults("fluid.tests.fluid5559Tree", { gradeNames: ["fluid.tests.onTestCaseStart.tree"], components: { testCases: { options: { modules: [ { name: "FLUID-5559 Double firing of onTestCaseStart and FLUID-5633 listener deregistration", tests: [{ name: "FLUID-5559 sequence", expect: 4, sequence: [{ // Must use IoCSS here - see discussion on FLUID-4929 - must avoid triggering construction event: "{fluid5559Tree targetTree}.events.hearIt", // Use a bare listener this first time to test one variant of fluid.test.findListenerId listener: "fluid.tests.onTestCaseStart.assertValue" }, { func: "fluid.tests.onTestCaseStart.assertValue", args: "{targetTree}" }, { // Try firing the event again in order to test FLUID-5633 func: "{fluid5559Tree}.targetTree.events.hearIt.fire", args: 5 }, { event: "{fluid5559Tree targetTree}.events.hearIt", listener: "jqUnit.assertEquals", args: ["Resolved value from 2nd firing", 5, "{arguments}.0"] }, { // Try firing the event again in order to test FLUID-5633 further func: "{fluid5559Tree}.targetTree.events.hearIt.fire", args: true }, { event: "{fluid5559Tree targetTree}.events.hearIt", listener: "jqUnit.assertEquals", args: ["Resolved value from 3rd firing", true, "{arguments}.0"] }] }] }] } } } }); fluid.tests.onTestCaseStart.assertValue = function (arg) { jqUnit.assertValue("Received value", arg); }; fluid.defaults("fluid.tests.fluid5633Tree", { gradeNames: ["fluid.test.testEnvironment", "fluid.test.testCaseHolder"], events: { createIt: null }, components: { dynamic: { type: "fluid.component", createOnEvent: "createIt", options: { value: "{arguments}.0" } } }, modules: [{ name: "FLUID-5633 Deregistration of IoCSS listeners", tests: [{ name: "FLUID-5633 sequence", expect: 3, sequence: [{ func: "{fluid5633Tree}.events.createIt.fire", args: 1 }, { event: "{fluid5633Tree dynamic}.events.onCreate", listener: "fluid.tests.onTestCaseStart.assertValue" }, { func: "{fluid5633Tree}.events.createIt.fire", args: 2 }, { event: "{fluid5633Tree dynamic}.events.onCreate", // Use a different listener handle here to test for accumulation listener: "fluid.tests.fluid5633Tree.assertValue2" }, { func: "{fluid5633Tree}.events.createIt.fire", args: 2 }, { event: "{fluid5633Tree dynamic}.events.onCreate", listener: "jqUnit.assertEquals", args: ["Resolved value from 3rd firing", 2, "{arguments}.0.options.value"] }] }] }] }); fluid.tests.fluid5633Tree.assertValue2 = function (that) { jqUnit.assertEquals("Received argument from 2nd event firing", 2, that.options.value); }; // More ambitious test tree to flush out further cases observed by gmoss - // i) multi-component IoCSS selector // ii) injected event receiving listener // iii) selector matching by member name rather than context name fluid.defaults("fluid.tests.fluid5633Tree_2", { gradeNames: ["fluid.test.testEnvironment", "fluid.test.testCaseHolder"], events: { createAndBind: null }, components: { fluid5633top: { type: "fluid.component", options: { events: { createIt: null, bindIt: null }, components: { fluid5633middle: { type: "fluid.component", createOnEvent: "createIt", options: { components: { fluid5633bottom: { type: "fluid.component", options: { events: { bindIt: "{fluid5633top}.events.bindIt" } } } } } } } } } }, listeners: { createAndBind: "fluid.tests.fluid5633Tree_2.createAndBind" }, modules: [{ name: "FLUID-5633 strikes back: Deregistration of IoCSS listeners", tests: [{ name: "FLUID-5633 strikes back sequence", expect: 2, sequence: [{ func: "{fluid5633Tree_2}.events.createAndBind.fire", args: "{fluid5633Tree_2}" }, { event: "{fluid5633Tree_2 fluid5633middle fluid5633bottom}.events.bindIt", listener: "jqUnit.assertEquals", args: 42 }, { func: "{fluid5633Tree_2}.fluid5633top.events.bindIt.fire", args: 43 }, { event: "{fluid5633Tree_2 fluid5633middle fluid5633bottom}.events.bindIt", listener: "jqUnit.assertEquals", args: 43 }] }] }] }); fluid.tests.fluid5633Tree_2.createAndBind = function (that) { that.fluid5633top.events.createIt.fire(); that.fluid5633top.events.bindIt.fire(42); }; // FLUID-5575 late firing of onTestCaseStart // In this variant, we attach the onCreate listener directly, and refer to the // component eagerly - with the FLUID-5266 fix, this will now trigger an error if the event is late fluid.tests.onTestCaseStart.moduleSource = function (name) { var modules = [{ name: "FLUID-5575 Late firing of onTestCaseStart - " + name, tests: [{ name: "FLUID-5575 sequence" }] }]; var sequence = fluid.getGlobalValue(name); modules[0].tests[0] = $.extend(true, modules[0].tests[0], sequence); return modules; }; fluid.defaults("fluid.tests.fluid5575Tree", { gradeNames: ["fluid.tests.onTestCaseStart.tree"], components: { targetTree: { options: { events: { triggerable: null // used in "activePassive" case }, listeners: { onCreate: "fluid.tests.onTestCaseStart.assertValue" } } }, testCases: { options: { moduleSource: { func: "fluid.tests.onTestCaseStart.moduleSource", args: "{testEnvironment}.options.sequenceName" } } } } }); fluid.tests.onTestCaseStart.singleActive = { expect: 2, sequence: [{ func: "fluid.tests.onTestCaseStart.assertValue", args: "{targetTree}" }] }; fluid.defaults("fluid.tests.fluid5575Tree.singleActive", { gradeNames: ["fluid.tests.fluid5575Tree"], sequenceName: "fluid.tests.onTestCaseStart.singleActive" }); fluid.tests.onTestCaseStart.doubleActive = { expect: 3, sequence: [{ func: "fluid.tests.onTestCaseStart.assertValue", args: "{targetTree}" }, { func: "fluid.tests.onTestCaseStart.assertValue", args: "{targetTree}" }] }; fluid.defaults("fluid.tests.fluid5575Tree.doubleActive", { gradeNames: ["fluid.tests.fluid5575Tree"], sequenceName: "fluid.tests.onTestCaseStart.doubleActive" }); // This case occurs in metadata feedback tests - "decodeEvent" for the upcoming passive fixture // would itself trigger creation before active starts fluid.tests.onTestCaseStart.activePassive = { expect: 2, sequence: [{ func: "{targetTree}.events.triggerable.fire", args: "{targetTree}" }, { event: "{targetTree}.events.triggerable", listener: "fluid.tests.onTestCaseStart.assertValue" }] }; fluid.defaults("fluid.tests.fluid5575Tree.activePassive", { gradeNames: ["fluid.tests.fluid5575Tree"], sequenceName: "fluid.tests.onTestCaseStart.activePassive" }); /** FLUID-5753, FLUID-5949: promise/task support and coincident environment and testCaseHolder **/ fluid.defaults("fluid.tests.taskTester", { gradeNames: ["fluid.test.testEnvironment", "fluid.test.testCaseHolder"], invokers: { resolvedPromiseDispenser: "fluid.tests.promiseDispenser({arguments}.0, resolve)", rejectedPromiseDispenser: "fluid.tests.promiseDispenser({arguments}.0, reject)" }, modules: [{ name: "FLUID-5949 Task/promise-based testing", tests: [{ name: "Sequence with single resolve member", expect: 1, sequence: [{ task: "{taskTester}.resolvedPromiseDispenser", args: 42, resolve: "fluid.tests.expect42" }] }, { name: "Sequence with resolve and reject with their own args", expect: 3, sequence: [{ task: "{taskTester}.resolvedPromiseDispenser", args: 42, resolve: "jqUnit.assertDeepEq", resolveArgs: ["The resolve argument is 42", 42, "{arguments}.0"] }, { task: "{taskTester}.rejectedPromiseDispenser", args: 42, reject: "jqUnit.assertDeepEq", rejectArgs: ["The totality of the reject arguments is 42", [42], "{arguments}"] }, { task: "{taskTester}.resolvedPromiseDispenser", args: [[true, false]], resolve: "jqUnit.assertDeepEq", resolveArgs: ["The resolve argument is [true, false]", [true, false], "{arguments}.0"] }] }, { name: "Failing tests: resolve for reject and reject for resolve", expect: 2, sequence: [{ funcName: "fluid.test.failingSetup" }, { task: "{taskTester}.rejectedPromiseDispenser", args: 42, resolve: "fluid.fail", resolveArgs: "This should never run" }, { task: "{taskTester}.resolvedPromiseDispenser", args: 42, reject: "fluid.fail", rejectArgs: "This should never run" }, { funcName: "fluid.test.failingTeardown" }] }] }] }); fluid.tests.expect42 = function () { jqUnit.assertDeepEq("The totality of the arguments is 42", [42], fluid.makeArray(arguments)); }; fluid.tests.promiseDispenser = function (arg, method) { var togo = fluid.promise(); fluid.invokeLater(function () { togo[method](arg); }); return togo; }; /** FLUID-5903: Priority-driven "grade budding system" **/ fluid.defaults("fluid.tests.elementPriority.beginning", { gradeNames: "fluid.test.sequenceElement", sequence: [{ func: "{testCaseHolder}.pushRecord(beginning)" }] }); fluid.defaults("fluid.tests.elementPriority.postBeginning", { gradeNames: "fluid.test.sequenceElement", sequence: [{ func: "{testCaseHolder}.pushRecord(postBeginning)" }] }); fluid.defaults("fluid.tests.elementPriority.end", { gradeNames: "fluid.test.sequenceElement", sequence: [{ func: "{testCaseHolder}.pushRecord(end)" }] }); fluid.defaults("fluid.tests.elementPriority.check", { gradeNames: "fluid.test.sequenceElement", mergePolicy: { targetComponent: "noexpand" }, // A placeholder reference to test possibility for recursive context references targetComponent: "{placeHolder}", sequence: [{ func: "fluid.tests.elementPriority.checkSequence({{that}.options.targetComponent}.record)" }] }); fluid.tests.elementPriority.checkSequence = function (record) { jqUnit.assertDeepEq("Sequence elements executed in correct order", ["beginning", "postBeginning", "sequence", "end"], record); }; fluid.defaults("fluid.tests.elementPrioritySequence", { gradeNames: "fluid.test.sequence", sequenceElements: { check: { gradeNames: "fluid.tests.elementPriority.check", options: { targetComponent: "{testCaseHolder}" }, priority: "after:end" }, end: { gradeNames: "fluid.tests.elementPriority.end", priority: "after:sequence" }, postBeginning: { gradeNames: "fluid.tests.elementPriority.postBeginning", priority: "after:beginning" }, beginning: { gradeNames: "fluid.tests.elementPriority.beginning", priority: "before:sequence" } } }); fluid.tests.elementPriority.pushRecord = function (record, toPush) { record.push(toPush); }; fluid.defaults("fluid.tests.elementPriority", { gradeNames: ["fluid.test.testEnvironment", "fluid.test.testCaseHolder"], members: { record: [] }, invokers: { pushRecord: "fluid.tests.elementPriority.pushRecord({testCaseHolder}.record, {arguments}.0)" }, modules: [{ name: "FLUID-5903: Priority-driven grade budding", tests: [{ expect: 1, name: "Simple sequence of 4 active elements", sequenceGrade: "fluid.tests.elementPrioritySequence", sequence: [{ func: "{testCaseHolder}.pushRecord(sequence)" }] } ] }] }); /** Global driver function **/ fluid.tests.IoCTestingTests = function () { fluid.test.runTests([ "fluid.tests.myTestTree" ]); fluid.invokeLater(function () { fluid.test.runTests([ "fluid.tests.sourceTester", "fluid.tests.hangTester", "fluid.tests.listenerArg", "fluid.tests.modelTestTree", "fluid.tests.fluid5559Tree", "fluid.tests.fluid5633Tree", "fluid.tests.fluid5633Tree_2", "fluid.tests.fluid5575Tree.singleActive", "fluid.tests.fluid5575Tree.doubleActive", "fluid.tests.fluid5575Tree.activePassive", "fluid.tests.taskTester", "fluid.tests.elementPriority" ]); }); };