diff --git a/packages/doenetml-worker/src/components/dynamicalSystems/ODESystem.js b/packages/doenetml-worker/src/components/dynamicalSystems/ODESystem.js
index bddbaba9e..d47d3bf92 100644
--- a/packages/doenetml-worker/src/components/dynamicalSystems/ODESystem.js
+++ b/packages/doenetml-worker/src/components/dynamicalSystems/ODESystem.js
@@ -558,7 +558,7 @@ export default class ODESystem extends InlineComponent {
},
}),
definition({ dependencyValues }) {
- console.log(dependencyValues);
+ // console.log(dependencyValues);
let warnings = [];
let valid = true;
diff --git a/packages/doenetml-worker/src/test/dynamicalsystem/cobwebpolyline.test.ts b/packages/doenetml-worker/src/test/dynamicalsystem/cobwebpolyline.test.ts
new file mode 100644
index 000000000..e0581a4a9
--- /dev/null
+++ b/packages/doenetml-worker/src/test/dynamicalsystem/cobwebpolyline.test.ts
@@ -0,0 +1,407 @@
+import { describe, expect, it, vi } from "vitest";
+import { createTestCore, returnAllStateVariables } from "../utils/test-core";
+import {
+ movePolyline,
+ submitAnswer,
+ updateMathInputValue,
+ updateValue,
+} from "../utils/actions";
+
+const Mock = vi.fn();
+vi.stubGlobal("postMessage", Mock);
+vi.mock("hyperformula");
+
+describe("CobwebPolyline Tag Tests", async () => {
+ it("logistic system", async () => {
+ let core = await createTestCore({
+ doenetML: `
+ 1/3*x*(3-x)+x
+ 1
+
+
+
+
+
+
+
+
+
Submitted responses are the vertices of the polyline: $check_cobweb.submittedResponses{displayDigits="5"}
+ Current responses are the vertices of the polyline: $check_cobweb.currentResponses{displayDigits="5"}
+ `,
+ });
+
+ let latexResults = ["x_{ 0 } & = -1.5"];
+ let submittedVertices: string[] = [];
+ let currentVertices = ["( -1.5, 0 )"];
+ let initialValCredit = 0;
+ let cobwebCredit = 0;
+ let cobwebJustSubmitted = false;
+
+ async function check_items() {
+ let stateVariables = await returnAllStateVariables(core);
+ // check scores
+ expect(
+ stateVariables["/check_initial"].stateValues.creditAchieved,
+ ).eqls(initialValCredit);
+ expect(
+ stateVariables["/check_cobweb"].stateValues.creditAchieved,
+ ).eqls(cobwebCredit);
+ expect(
+ stateVariables["/check_cobweb"].stateValues.justSubmitted,
+ ).eqls(cobwebJustSubmitted);
+ // check numPoints
+ expect(stateVariables["/numPoints"].stateValues.value).eqls(
+ currentVertices.length,
+ );
+ // check math rows
+ let mdChildren = stateVariables["/md1"].activeChildren;
+ expect(mdChildren.length).eqls(latexResults.length);
+ for (let i = 0; i < latexResults.length; i++) {
+ let childName = mdChildren[i].componentName;
+ expect(stateVariables[childName].stateValues.latex).eqls(
+ latexResults[i],
+ );
+ }
+ // check submitted vertices via paragraph
+ let allSubmittedVertices = submittedVertices.reduce(
+ (a, v) => `${a}, ${v}`,
+ "",
+ );
+ if (allSubmittedVertices.length > 0) {
+ allSubmittedVertices = allSubmittedVertices.substring(2);
+ }
+ expect(stateVariables["/psr"].stateValues.text).eqls(
+ `Submitted responses are the vertices of the polyline: ${allSubmittedVertices}`,
+ );
+
+ // check submitted vertices via paragraph
+ let allCurrentVertices = currentVertices.reduce(
+ (a, v) => `${a}, ${v}`,
+ "",
+ );
+ if (allCurrentVertices.length > 0) {
+ allCurrentVertices = allCurrentVertices.substring(2);
+ }
+ expect(stateVariables["/pcr"].stateValues.text).eqls(
+ `Current responses are the vertices of the polyline: ${allCurrentVertices}`,
+ );
+ }
+
+ await check_items();
+ // Also check can't remove line
+ {
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/deleteline"].stateValues.hidden).eqls(true);
+ }
+
+ // Click both submit buttons
+ submittedVertices = [...currentVertices];
+ cobwebJustSubmitted = true;
+ await submitAnswer({ name: "/check_initial", core });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Move first point
+ currentVertices[0] = "( 1, 0 )";
+ latexResults[0] = "x_{ 0 } & = 1";
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 0: [1, 0] },
+ core,
+ });
+ await check_items();
+
+ // Click initial value submit
+ initialValCredit = 1;
+ await submitAnswer({ name: "/check_initial", core });
+ await check_items();
+
+ // Add second point, should spawn at center of graph
+ const graphCenterX = (-2 + 5) / 2;
+ const graphCenterY = (-2.2 + 4.5) / 2;
+ latexResults.push(`x_{ 1 } & = ${graphCenterY}`);
+ currentVertices.push(`( ${graphCenterX}, ${graphCenterY} )`);
+ cobwebJustSubmitted = false;
+ await updateValue({ name: "/addline", core });
+ await check_items();
+
+ // Move second point to wrong location, submit
+ latexResults[1] = "x_{ 1 } & = 4";
+ currentVertices[1] = "( 3, 4 )";
+ submittedVertices = [...currentVertices];
+ cobwebJustSubmitted = true;
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 1: [3, 4] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Move second point to a different wrong location and make sure submit button reappears
+ latexResults[1] = "x_{ 1 } & = 1";
+ currentVertices[1] = "( 1, 1 )";
+ cobwebJustSubmitted = false;
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 1: [1, 1] },
+ core,
+ });
+ await check_items();
+
+ // submit
+ submittedVertices = [...currentVertices];
+ cobwebJustSubmitted = true;
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Move second point to correct location, submit
+ latexResults[1] = "x_{ 1 } & = 1.6667";
+ currentVertices[1] = "( 1, 1.6667 )";
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 0.2;
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 1: [1, 1.6] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Add third point but don't move it, should be at graph's center, submit
+ currentVertices.push(`( ${graphCenterX}, ${graphCenterY} )`);
+ submittedVertices = [...currentVertices];
+ await updateValue({ name: "/addline", core });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Move third point to correct location, submit
+ currentVertices[2] = "( 1.6667, 1.6667 )";
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 0.4;
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 2: [1.6, 1.6] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Add fourth point and move to wrong location, submit
+ latexResults.push("x_{ 2 } & = 2");
+ currentVertices.push(`( 1, 2 )`);
+ submittedVertices = [...currentVertices];
+ await updateValue({ name: "/addline", core });
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 3: [1, 2] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Move fourth point to correct location, submit
+ latexResults[2] = "x_{ 2 } & = 2.4074";
+ currentVertices[3] = "( 1.6667, 2.4074 )";
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 0.6;
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 3: [1.6, 2.4] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Delete fourth point
+ let removedLatex = latexResults.pop()!;
+ let removedVertex = currentVertices.pop()!;
+ cobwebJustSubmitted = false;
+ await updateValue({ name: "/deleteline", core });
+ await check_items();
+
+ // submit
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 0.4;
+ cobwebJustSubmitted = true;
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Add fourth point back, should remember where it had been, submit
+ await updateValue({ name: "/addline", core });
+ latexResults.push(removedLatex);
+ currentVertices.push(removedVertex);
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 0.6;
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Add fifth point and move to correct location, submit
+ currentVertices.push(`( 2.4074, 2.4074 )`);
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 0.8;
+ await updateValue({ name: "/addline", core });
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 4: [2.4, 2.4] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Add sixth point and move to wrong location, submit
+ latexResults.push("x_{ 3 } & = 3");
+ currentVertices.push(`( -1, 3 )`);
+ submittedVertices = [...currentVertices];
+ await updateValue({ name: "/addline", core });
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 5: [-1, 3] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Move sixth point to correct location, submit
+ latexResults[3] = "x_{ 3 } & = 2.8829";
+ currentVertices[5] = "( 2.4074, 2.8829 )";
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 1;
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 5: [2.4, 3] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Add seventh point and move to wrong location, submit
+ currentVertices.push(`( 3, 1 )`);
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 5 / 6; // ~0.83
+ await updateValue({ name: "/addline", core });
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 6: [3, 1] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Move seventh point to correct location, submit
+ currentVertices[6] = "( 2.8829, 2.8829 )";
+ submittedVertices = [...currentVertices];
+ cobwebCredit = 1;
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 6: [3, 3] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+
+ // Add eighth point and move to correct location, submit
+ latexResults[4] = "x_{ 4 } & = 2.9954";
+ currentVertices[7] = "( 2.8829, 2.9954 )";
+ submittedVertices = [...currentVertices];
+ await updateValue({ name: "/addline", core });
+ await movePolyline({
+ name: "/graph1/cobweb",
+ pointCoords: { 7: [3, 3] },
+ core,
+ });
+ await submitAnswer({ name: "/check_cobweb", core });
+ await check_items();
+ });
+
+ it("handle bad initial point, lock to solution", async () => {
+ let core = await createTestCore({
+ doenetML: `
+
+ x^2
+
+ Initial point:
+
+
+
+ `,
+ });
+
+ let stateVariables = await returnAllStateVariables(core);
+ let vertices = stateVariables["/cobweb"].stateValues.vertices;
+ expect(vertices.length).eqls(100);
+ expect(vertices[0].map((v) => v.tree)).eqls(["_", 0]);
+ for (let i = 1; i < 100; i++) {
+ expect(vertices[i].map((v) => v.tree)).eqls([NaN, NaN]);
+ }
+
+ await updateMathInputValue({ name: "/x0", latex: "0.9", core });
+ stateVariables = await returnAllStateVariables(core);
+ vertices = stateVariables["/cobweb"].stateValues.vertices;
+ expect(vertices.length).eqls(100);
+ expect(vertices[0].map((v) => v.tree)).eqls([0.9, 0]);
+ expect(vertices[1].map((v) => v.tree)).eqls([0.9, 0.81]);
+ expect(vertices[50].map((v) => v.tree)).eqls([0, 0]);
+ expect(vertices[99].map((v) => v.tree)).eqls([0, 0]);
+
+ await updateMathInputValue({ name: "/x0", latex: "(1.1,3)", core });
+ stateVariables = await returnAllStateVariables(core);
+ vertices = stateVariables["/cobweb"].stateValues.vertices;
+ expect(vertices.length).eqls(100);
+ expect(vertices[0][0].tree).closeTo(1.1, 1e-14);
+ expect(vertices[0][1].tree).closeTo(3, 1e-14);
+ expect(vertices[1][0].tree).closeTo(1.1, 1e-14);
+ expect(vertices[1][1].tree).closeTo(1.21, 1e-14);
+ expect(vertices[50].map((v) => v.tree)).eqls([Infinity, Infinity]);
+ expect(vertices[99].map((v) => v.tree)).eqls([Infinity, Infinity]);
+ });
+});
diff --git a/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumcurve.test.ts b/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumcurve.test.ts
new file mode 100644
index 000000000..fdbb3e75e
--- /dev/null
+++ b/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumcurve.test.ts
@@ -0,0 +1,158 @@
+import { describe, expect, it, vi } from "vitest";
+import { createTestCore, returnAllStateVariables } from "../utils/test-core";
+import { updateBooleanInputValue } from "../utils/actions";
+
+const Mock = vi.fn();
+vi.stubGlobal("postMessage", Mock);
+vi.mock("hyperformula");
+
+describe("Equilibriumcurve Tag Tests", async () => {
+ it("equilibriumcurve change stable", async () => {
+ let core = await createTestCore({
+ doenetML: `
+
+
+
+
+
+
+
+
+
+
+
+ $(g/A.stable{assignNames="gAs"})
+ $(g/B.stable{assignNames="gBs"})
+ $(g/C.stable{assignNames="gCs"})
+ $(g/D.stable{assignNames="gDs"})
+
+
+
+ $g{name="g2"}
+
+
+ $(g2/A.stable{assignNames="g2As"})
+ $(g2/B.stable{assignNames="g2Bs"})
+ $(g2/C.stable{assignNames="g2Cs"})
+ $(g2/D.stable{assignNames="g2Ds"})
+
+
`,
+ });
+
+ const throughA = [
+ [1, 2],
+ [3, 4],
+ [2, 6],
+ ];
+ const throughB = [
+ [3, 2],
+ [5, 4],
+ [4, 6],
+ ];
+ const throughC = [
+ [-3, 2],
+ [-5, 4],
+ [-4, 6],
+ ];
+ const throughD = [
+ [-1, 2],
+ [-3, 4],
+ [-2, 6],
+ ];
+ let svs = await returnAllStateVariables(core);
+ expect(svs["/g/A"].stateValues.numericalThroughPoints).eqls(throughA);
+ expect(svs["/g/B"].stateValues.numericalThroughPoints).eqls(throughB);
+ expect(svs["/g/C"].stateValues.numericalThroughPoints).eqls(throughC);
+ expect(svs["/g/D"].stateValues.numericalThroughPoints).eqls(throughD);
+ expect(svs["/g2/A"].stateValues.numericalThroughPoints).eqls(throughA);
+ expect(svs["/g2/B"].stateValues.numericalThroughPoints).eqls(throughB);
+ expect(svs["/g2/C"].stateValues.numericalThroughPoints).eqls(throughC);
+ expect(svs["/g2/D"].stateValues.numericalThroughPoints).eqls(throughD);
+
+ let As = true;
+ let Cs = false;
+ let Ds = false;
+
+ async function check_stable() {
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/gAs"].stateValues.value).eqls(As);
+ expect(stateVariables["/gBs"].stateValues.value).eqls(false);
+ expect(stateVariables["/gCs"].stateValues.value).eqls(Cs);
+ expect(stateVariables["/gDs"].stateValues.value).eqls(Ds);
+
+ expect(stateVariables["/g2As"].stateValues.value).eqls(As);
+ expect(stateVariables["/g2Bs"].stateValues.value).eqls(false);
+ expect(stateVariables["/g2Cs"].stateValues.value).eqls(Cs);
+ expect(stateVariables["/g2Ds"].stateValues.value).eqls(Ds);
+
+ expect(stateVariables["/g/A"].stateValues.stable).eq(As);
+ expect(stateVariables["/g/B"].stateValues.stable).eq(false);
+ expect(stateVariables["/g/C"].stateValues.stable).eq(Cs);
+ expect(stateVariables["/g/D"].stateValues.stable).eq(Ds);
+
+ expect(stateVariables["/g2/A"].stateValues.stable).eq(As);
+ expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
+ expect(stateVariables["/g2/C"].stateValues.stable).eq(Cs);
+ expect(stateVariables["/g2/D"].stateValues.stable).eq(Ds);
+ }
+
+ await check_stable();
+
+ // switch C via boolean input
+ Cs = !Cs;
+ await updateBooleanInputValue({ name: "/b1", boolean: Cs, core });
+ await check_stable();
+
+ // switch D via boolean input
+ Ds = !Ds;
+ await updateBooleanInputValue({ name: "/b2", boolean: Ds, core });
+ await check_stable();
+
+ // switch A via first action
+ As = !As;
+ await core.requestAction({
+ componentName: "/g/A",
+ actionName: "switchCurve",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // switch A via second action
+ As = !As;
+ await core.requestAction({
+ componentName: "/g2/A",
+ actionName: "switchCurve",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // cannot switch B via action
+ await core.requestAction({
+ componentName: "/g/B",
+ actionName: "switchCurve",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // cannot switch C via second action
+ await core.requestAction({
+ componentName: "/g2/C",
+ actionName: "switchCurve",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // switch D via second action
+ Ds = !Ds;
+ await core.requestAction({
+ componentName: "/g2/D",
+ actionName: "switchCurve",
+ args: {},
+ event: null,
+ });
+ });
+});
diff --git a/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumline.test.ts b/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumline.test.ts
new file mode 100644
index 000000000..c88061bb1
--- /dev/null
+++ b/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumline.test.ts
@@ -0,0 +1,140 @@
+import { describe, expect, it, vi } from "vitest";
+import { createTestCore, returnAllStateVariables } from "../utils/test-core";
+import { updateBooleanInputValue } from "../utils/actions";
+
+const Mock = vi.fn();
+vi.stubGlobal("postMessage", Mock);
+vi.mock("hyperformula");
+
+describe("Equilibriumline Tag Tests", async () => {
+ it("equilibriumline change stable", async () => {
+ let core = await createTestCore({
+ doenetML: `
+
+ y=4
+ y=7
+ y=-9
+ y=-3
+
+
+
+
+
+
+ $(g/A.stable{assignNames="gAs"})
+ $(g/B.stable{assignNames="gBs"})
+ $(g/C.stable{assignNames="gCs"})
+ $(g/D.stable{assignNames="gDs"})
+
+
+
+ $g{name="g2"}
+
+
+ $(g2/A.stable{assignNames="g2As"})
+ $(g2/B.stable{assignNames="g2Bs"})
+ $(g2/C.stable{assignNames="g2Cs"})
+ $(g2/D.stable{assignNames="g2Ds"})
+
+
+ `,
+ });
+
+ const equationA = ["=", "y", 4];
+ const equationB = ["=", "y", 7];
+ const equationC = ["=", "y", -9];
+ const equationD = ["=", "y", -3];
+ let svs = await returnAllStateVariables(core);
+ expect(svs["/g/A"].stateValues.equation.tree).eqls(equationA);
+ expect(svs["/g/B"].stateValues.equation.tree).eqls(equationB);
+ expect(svs["/g/C"].stateValues.equation.tree).eqls(equationC);
+ expect(svs["/g/D"].stateValues.equation.tree).eqls(equationD);
+ expect(svs["/g2/A"].stateValues.equation.tree).eqls(equationA);
+ expect(svs["/g2/B"].stateValues.equation.tree).eqls(equationB);
+ expect(svs["/g2/C"].stateValues.equation.tree).eqls(equationC);
+ expect(svs["/g2/D"].stateValues.equation.tree).eqls(equationD);
+
+ let As = true;
+ let Cs = false;
+ let Ds = false;
+
+ async function check_stable() {
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/gAs"].stateValues.value).eqls(As);
+ expect(stateVariables["/gBs"].stateValues.value).eqls(false);
+ expect(stateVariables["/gCs"].stateValues.value).eqls(Cs);
+ expect(stateVariables["/gDs"].stateValues.value).eqls(Ds);
+ expect(stateVariables["/g2As"].stateValues.value).eqls(As);
+ expect(stateVariables["/g2Bs"].stateValues.value).eqls(false);
+ expect(stateVariables["/g2Cs"].stateValues.value).eqls(Cs);
+ expect(stateVariables["/g2Ds"].stateValues.value).eqls(Ds);
+ expect(stateVariables["/g/A"].stateValues.stable).eq(As);
+ expect(stateVariables["/g/B"].stateValues.stable).eq(false);
+ expect(stateVariables["/g/C"].stateValues.stable).eq(Cs);
+ expect(stateVariables["/g/D"].stateValues.stable).eq(Ds);
+ expect(stateVariables["/g2/A"].stateValues.stable).eq(As);
+ expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
+ expect(stateVariables["/g2/C"].stateValues.stable).eq(Cs);
+ expect(stateVariables["/g2/D"].stateValues.stable).eq(Ds);
+ }
+
+ await check_stable();
+
+ // switch C via boolean input
+ Cs = !Cs;
+ await updateBooleanInputValue({ name: "/b1", boolean: Cs, core });
+ await check_stable();
+
+ // switch D via boolean input
+ Ds = !Ds;
+ await updateBooleanInputValue({ name: "/b2", boolean: Ds, core });
+ await check_stable();
+
+ // switch A via first action
+ As = !As;
+ await core.requestAction({
+ componentName: "/g/A",
+ actionName: "switchLine",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // switch A via second action
+ As = !As;
+ await core.requestAction({
+ componentName: "/g2/A",
+ actionName: "switchLine",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // cannot switch B via action
+ await core.requestAction({
+ componentName: "/g/B",
+ actionName: "switchLine",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // cannot switch C via second action
+ await core.requestAction({
+ componentName: "/g2/C",
+ actionName: "switchLine",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // switch D via second action
+ Ds = !Ds;
+ await core.requestAction({
+ componentName: "/g2/D",
+ actionName: "switchLine",
+ args: {},
+ event: null,
+ });
+ });
+});
diff --git a/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumpoint.test.ts b/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumpoint.test.ts
new file mode 100644
index 000000000..90c23bef3
--- /dev/null
+++ b/packages/doenetml-worker/src/test/dynamicalsystem/equilibriumpoint.test.ts
@@ -0,0 +1,140 @@
+import { describe, expect, it, vi } from "vitest";
+import { createTestCore, returnAllStateVariables } from "../utils/test-core";
+import { updateBooleanInputValue } from "../utils/actions";
+
+const Mock = vi.fn();
+vi.stubGlobal("postMessage", Mock);
+vi.mock("hyperformula");
+
+describe("Equilibriumpoint Tag Tests", async () => {
+ it("equilibriumpoint change stable", async () => {
+ let core = await createTestCore({
+ doenetML: `
+
+ (4,0)
+ (7,0)
+ (-9,0)
+ (-3,0)
+
+
+
+
+
+
+ $(g/A.stable{assignNames="gAs"})
+ $(g/B.stable{assignNames="gBs"})
+ $(g/C.stable{assignNames="gCs"})
+ $(g/D.stable{assignNames="gDs"})
+
+
+
+ $g{name="g2"}
+
+
+ $(g2/A.stable{assignNames="g2As"})
+ $(g2/B.stable{assignNames="g2Bs"})
+ $(g2/C.stable{assignNames="g2Cs"})
+ $(g2/D.stable{assignNames="g2Ds"})
+
+
+ `,
+ });
+
+ const pointA = [4, 0];
+ const pointB = [7, 0];
+ const pointC = [-9, 0];
+ const pointD = [-3, 0];
+ let svs = await returnAllStateVariables(core);
+ expect(svs["/g/A"].stateValues.xs.map((v) => v.tree)).eqls(pointA);
+ expect(svs["/g/B"].stateValues.xs.map((v) => v.tree)).eqls(pointB);
+ expect(svs["/g/C"].stateValues.xs.map((v) => v.tree)).eqls(pointC);
+ expect(svs["/g/D"].stateValues.xs.map((v) => v.tree)).eqls(pointD);
+ expect(svs["/g2/A"].stateValues.xs.map((v) => v.tree)).eqls(pointA);
+ expect(svs["/g2/B"].stateValues.xs.map((v) => v.tree)).eqls(pointB);
+ expect(svs["/g2/C"].stateValues.xs.map((v) => v.tree)).eqls(pointC);
+ expect(svs["/g2/D"].stateValues.xs.map((v) => v.tree)).eqls(pointD);
+
+ let As = true;
+ let Cs = false;
+ let Ds = false;
+
+ async function check_stable() {
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/gAs"].stateValues.value).eqls(As);
+ expect(stateVariables["/gBs"].stateValues.value).eqls(false);
+ expect(stateVariables["/gCs"].stateValues.value).eqls(Cs);
+ expect(stateVariables["/gDs"].stateValues.value).eqls(Ds);
+ expect(stateVariables["/g2As"].stateValues.value).eqls(As);
+ expect(stateVariables["/g2Bs"].stateValues.value).eqls(false);
+ expect(stateVariables["/g2Cs"].stateValues.value).eqls(Cs);
+ expect(stateVariables["/g2Ds"].stateValues.value).eqls(Ds);
+ expect(stateVariables["/g/A"].stateValues.stable).eq(As);
+ expect(stateVariables["/g/B"].stateValues.stable).eq(false);
+ expect(stateVariables["/g/C"].stateValues.stable).eq(Cs);
+ expect(stateVariables["/g/D"].stateValues.stable).eq(Ds);
+ expect(stateVariables["/g2/A"].stateValues.stable).eq(As);
+ expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
+ expect(stateVariables["/g2/C"].stateValues.stable).eq(Cs);
+ expect(stateVariables["/g2/D"].stateValues.stable).eq(Ds);
+ }
+
+ await check_stable();
+
+ // switch C via boolean input
+ Cs = !Cs;
+ await updateBooleanInputValue({ name: "/b1", boolean: Cs, core });
+ await check_stable();
+
+ // switch D via boolean input
+ Ds = !Ds;
+ await updateBooleanInputValue({ name: "/b2", boolean: Ds, core });
+ await check_stable();
+
+ // switch A via first action
+ As = !As;
+ await core.requestAction({
+ componentName: "/g/A",
+ actionName: "switchPoint",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // switch A via second action
+ As = !As;
+ await core.requestAction({
+ componentName: "/g2/A",
+ actionName: "switchPoint",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // cannot switch B via action
+ await core.requestAction({
+ componentName: "/g/B",
+ actionName: "switchPoint",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // cannot switch C via second action
+ await core.requestAction({
+ componentName: "/g2/C",
+ actionName: "switchPoint",
+ args: {},
+ event: null,
+ });
+ await check_stable();
+
+ // switch D via second action
+ Ds = !Ds;
+ await core.requestAction({
+ componentName: "/g2/D",
+ actionName: "switchPoint",
+ args: {},
+ event: null,
+ });
+ });
+});
diff --git a/packages/doenetml-worker/src/test/dynamicalsystem/odesystem.test.ts b/packages/doenetml-worker/src/test/dynamicalsystem/odesystem.test.ts
new file mode 100644
index 000000000..229a7070b
--- /dev/null
+++ b/packages/doenetml-worker/src/test/dynamicalsystem/odesystem.test.ts
@@ -0,0 +1,808 @@
+import { describe, expect, it, vi } from "vitest";
+import { createTestCore, returnAllStateVariables } from "../utils/test-core";
+import { createFunctionFromDefinition } from "@doenet/utils";
+import {
+ movePoint,
+ updateBooleanInputValue,
+ updateMathInputValue,
+} from "../utils/actions";
+
+const Mock = vi.fn();
+vi.stubGlobal("postMessage", Mock);
+vi.mock("hyperformula");
+
+describe("ODEsystem Tag Tests", async () => {
+ it("1D linear system", async () => {
+ let core = await createTestCore({
+ doenetML: `
+a =
+initial condition =
+tol =
+
+
+ $a x
+
+
+
+ $ode.numericalSolution{assignNames="f"}
+
+
+
+
+
+0
+$tol.value{assignNames="tol2"}
+ `,
+ });
+
+ let ic = 1;
+ let a = 1;
+ let tol = 1e-6;
+ let expectedF = (x) => ic * Math.exp(a * x);
+
+ async function check_items() {
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/tol2"].stateValues.value.tree).eqls(tol);
+ expect(stateVariables["/ode"].stateValues.latex).eqls(
+ `\\frac{dx}{dt} &= ${a === 1 ? "" : a + " "}x\\notag\\\\x(0) &= ${ic}\\notag`,
+ );
+ let solutionF = createFunctionFromDefinition(
+ stateVariables["/ode"].stateValues
+ .numericalSolutionFDefinitions[0],
+ );
+
+ let solutionsFromCore = stateVariables["/map1"]
+ .replacements!.map(
+ (child) =>
+ stateVariables[child.componentName].replacements![0],
+ )
+ .map(
+ (grandChild) =>
+ stateVariables[grandChild.componentName].stateValues
+ .value,
+ )
+ .map((v) => v.tree);
+
+ for (let x = 0; x <= 5; x += 0.5) {
+ expect(solutionF(x)).closeTo(
+ expectedF(x),
+ tol * Math.max(1, Math.abs(expectedF(x))),
+ );
+ expect(solutionsFromCore[2 * x]).eq(solutionF(x));
+ }
+ }
+
+ await check_items();
+
+ // Change initial condition
+ ic = 3;
+ expectedF = (x) => ic * Math.exp(a * x);
+ await updateMathInputValue({ name: "/ic", latex: "3", core });
+ await check_items();
+
+ // Change parameter
+ a = -2;
+ expectedF = (x) => ic * Math.exp(a * x);
+ await updateMathInputValue({ name: "/a", latex: "-2", core });
+ await check_items();
+
+ // Change ic with point
+ ic = -5;
+ expectedF = (x) => ic * Math.exp(a * x);
+ await movePoint({ name: "/point1", x: 0, y: ic, core });
+ await check_items();
+
+ // Change tolerance
+ tol = 1e-10;
+ await updateMathInputValue({ name: "/tol", latex: "1E-10", core });
+
+ // Change parameter again
+ a = 0.5;
+ expectedF = (x) => ic * Math.exp(a * x);
+ await updateMathInputValue({ name: "/a", latex: "0.5", core });
+ await check_items();
+
+ // Change initial condition to zero
+ ic = 0;
+ expectedF = (x) => 0;
+ await updateMathInputValue({ name: "/ic", latex: "0", core });
+ await check_items();
+ });
+
+ it("effect of max iterations, chunksize", async () => {
+ let core = await createTestCore({
+ doenetML: `
+ tol =
+ T =
+ maxIter =
+ chunkSize =
+
+ x
+
+
+ f($T) = $$(ode.numericalSolution)($T)
+ `,
+ });
+
+ let tol = 1e-6;
+ let T = 10;
+ let maxIter = 1000;
+ let chunkSize = 10;
+
+ async function check_items({
+ solverSuccess,
+ }: {
+ solverSuccess: boolean;
+ }) {
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/T"].stateValues.value.tree).eqls(T);
+ expect(stateVariables["/tol"].stateValues.value.tree).eqls(tol);
+ expect(stateVariables["/maxIter"].stateValues.value.tree).eqls(
+ maxIter,
+ );
+ expect(stateVariables["/chunkSize"].stateValues.value.tree).eqls(
+ chunkSize,
+ );
+
+ let solutionF = createFunctionFromDefinition(
+ stateVariables["/ode"].stateValues
+ .numericalSolutionFDefinitions[0],
+ );
+ let f_T_copied = Number(
+ stateVariables["/m1"].stateValues.text.split("=")[1],
+ );
+
+ if (!solverSuccess) {
+ // Ensure numerical solution at t=T is NaN
+ expect(solutionF(T)).eqls(NaN);
+ expect(f_T_copied).eqls(NaN);
+ } else {
+ // Ensure numerical solution for range [0,T] follows expected solution
+ const expectedF = (x) => Math.exp(x);
+ for (let x = 0; x <= T; x += 1) {
+ expect(solutionF(x)).closeTo(
+ expectedF(x),
+ tol * Math.max(1, Math.abs(expectedF(x))),
+ );
+ }
+ expect(f_T_copied).closeTo(
+ expectedF(T),
+ tol * Math.max(1, Math.abs(expectedF(T))),
+ );
+ }
+ }
+
+ await check_items({ solverSuccess: true });
+
+ // Solver algorithm runs past max iterations before it can
+ // solve f(20) within required threshold
+ T = 20;
+ await updateMathInputValue({ name: "/T", latex: `${T}`, core });
+ await check_items({ solverSuccess: false });
+
+ // increase max iterations, now f(20) works
+ maxIter = 2000;
+ await updateMathInputValue({
+ name: "/maxIter",
+ latex: `${maxIter}`,
+ core,
+ });
+ await check_items({ solverSuccess: true });
+
+ // Can't make it if decrease tolerance
+ tol = 1e-8;
+ await updateMathInputValue({ name: "/tol", latex: `1E-8`, core });
+ await check_items({ solverSuccess: false });
+
+ // increase max iterations further
+ maxIter = 5000;
+ await updateMathInputValue({
+ name: "/maxIter",
+ latex: `${maxIter}`,
+ core,
+ });
+ await check_items({ solverSuccess: true });
+
+ // decrease max iterations back down to original, fails
+ maxIter = 1000;
+ await updateMathInputValue({
+ name: "/maxIter",
+ latex: `${maxIter}`,
+ core,
+ });
+ await check_items({ solverSuccess: false });
+
+ // decrease chunksize
+ chunkSize = 1;
+ await updateMathInputValue({
+ name: "/chunkSize",
+ latex: `${chunkSize}`,
+ core,
+ });
+ await check_items({ solverSuccess: true });
+ });
+
+ it("change variables 1D", async () => {
+ let core = await createTestCore({
+ doenetML: `
+independent variable =
+dependent variable =
+
+
+ $dVar
+
+
+
+ $ode.numericalSolution{assignNames="f"}
+
+
+
+ `,
+ });
+
+ let tol = 1e-6;
+ let iVar = "t";
+ let dVar = "x";
+ let expectedF = (x) => Math.exp(x);
+
+ async function check_items() {
+ let stateVariables = await returnAllStateVariables(core);
+
+ expect(stateVariables["/ode"].stateValues.latex).eqls(
+ `\\frac{d${dVar}}{d${iVar}} &= ${dVar}\\notag\\\\${dVar}(0) &= 1\\notag`,
+ );
+ let solutionF = createFunctionFromDefinition(
+ stateVariables["/ode"].stateValues
+ .numericalSolutionFDefinitions[0],
+ );
+ let solutionsFromCore = stateVariables["/map1"].replacements!.map(
+ (x) =>
+ stateVariables[
+ stateVariables[x.componentName].replacements![0]
+ .componentName
+ ].stateValues.value.tree,
+ );
+
+ for (let t = 0; t <= 5; t += 1) {
+ if (Number.isNaN(expectedF(t))) {
+ expect(solutionF(t)).toBeNaN();
+ expect(solutionsFromCore[t]).toBeNaN();
+ } else {
+ expect(solutionF(t)).closeTo(
+ expectedF(t),
+ tol * Math.max(1, Math.abs(expectedF(t))),
+ );
+ expect(solutionsFromCore[t]).eq(solutionF(t));
+ }
+ }
+ }
+
+ await check_items();
+
+ // change independent variable
+ iVar = "s";
+ await updateMathInputValue({ name: "/iVar", latex: iVar, core });
+ await check_items();
+
+ // erase independent variable
+ iVar = "_";
+ expectedF = (x) => (x === 0 ? 1 : NaN);
+ await updateMathInputValue({ name: "/iVar", latex: "", core });
+ await check_items();
+
+ // restore independent variable
+ iVar = "u";
+ expectedF = (x) => Math.exp(x);
+ await updateMathInputValue({ name: "/iVar", latex: iVar, core });
+ await check_items();
+
+ // invalid independent variable
+ iVar = "1";
+ expectedF = (x) => (x === 0 ? 1 : NaN);
+ await updateMathInputValue({ name: "/iVar", latex: iVar, core });
+ await check_items();
+
+ // restore independent variable
+ iVar = "v";
+ expectedF = (x) => Math.exp(x);
+ await updateMathInputValue({ name: "/iVar", latex: iVar, core });
+ await check_items();
+
+ // change dependent variable
+ dVar = "z";
+ await updateMathInputValue({ name: "/dVar", latex: dVar, core });
+ await check_items();
+
+ // duplicate variable
+ dVar = iVar;
+ expectedF = (x) => (x === 0 ? 1 : NaN);
+ await updateMathInputValue({ name: "/dVar", latex: dVar, core });
+ await check_items();
+
+ // different dependent variable
+ dVar = "v_{1}";
+ expectedF = (x) => Math.exp(x);
+ await updateMathInputValue({ name: "/dVar", latex: "v_1", core });
+ await check_items();
+
+ // invalid dependent variable
+ dVar = "a b";
+ expectedF = (x) => (x === 0 ? 1 : NaN);
+ await updateMathInputValue({ name: "/dVar", latex: "ab", core });
+ await check_items();
+
+ // restore dependent variable
+ dVar = "a";
+ expectedF = (x) => Math.exp(x);
+ await updateMathInputValue({ name: "/dVar", latex: dVar, core });
+ await check_items();
+ });
+
+ it("display digits", async () => {
+ let core = await createTestCore({
+ doenetML: `
+display digits =
+
+ 0.123456789123456789x
+
+`,
+ });
+
+ let a = "0.1234567891";
+ let ic = "9.87654322";
+
+ async function check_items({ a, ic }: { a: string; ic: string }) {
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/ode"].stateValues.latex).eqls(
+ `\\frac{dx}{dt} &= ${a} x\\notag\\\\x(0) &= ${ic}\\notag`,
+ );
+ }
+ await check_items({ a, ic });
+
+ // 2 display digits
+ a = "0.12";
+ ic = "9.9";
+ await updateMathInputValue({ name: "/digits", latex: "2", core });
+ await check_items({ a, ic });
+
+ // 14 display digits
+ a = "0.12345678912346";
+ ic = "9.8765432198765";
+ await updateMathInputValue({ name: "/digits", latex: "14", core });
+ await check_items({ a, ic });
+ });
+
+ it("initial independent variable value", async () => {
+ let core = await createTestCore({
+ doenetML: `
+ initial t =
+ final t =
+
+
+ x
+
+
+ We started with
+ x($ode.initialIndependentVariableValue) = 1.
+
+ We end with
+ x($tf) = $$(ode.numericalSolution)($tf)
+`,
+ });
+
+ let t0 = 0;
+ let tf = 10;
+
+ async function check_items() {
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/ode"].stateValues.latex).eqls(
+ `\\frac{dx}{dt} &= x\\notag\\\\x(${t0}) &= 1\\notag`,
+ );
+
+ expect(
+ stateVariables["/ode"].stateValues
+ .initialIndependentVariableValue.tree,
+ ).eqls(t0);
+
+ let startPieces = stateVariables["/m1"].stateValues.latex
+ .split("=")
+ .map((v) => v.trim());
+ expect(startPieces.length).eqls(2);
+ expect(startPieces[0]).eqls(`x( ${t0} )`);
+
+ let finalPieces = stateVariables["/m2"].stateValues.latex
+ .split("=")
+ .map((v) => v.trim());
+ expect(finalPieces.length).eqls(2);
+ expect(finalPieces[0]).eqls(`x( ${tf} )`);
+ expect(Number(finalPieces[1])).closeTo(
+ Math.exp(tf - t0),
+ 1e-6 * Math.exp(tf - t0),
+ );
+ }
+
+ await check_items();
+
+ // Change initial time
+ t0 = -5;
+ await updateMathInputValue({ name: "/t0", latex: `${t0}`, core });
+ await check_items();
+
+ // Change initial and final time
+ t0 = 11;
+ tf = 12;
+ await updateMathInputValue({ name: "/t0", latex: `${t0}`, core });
+ await updateMathInputValue({ name: "/tf", latex: `${tf}`, core });
+ await check_items();
+ });
+
+ it("display initial conditions", async () => {
+ let core = await createTestCore({
+ doenetML: `
+ display initial conditions:
+
+ x
+
+`,
+ });
+
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/ode"].stateValues.latex).eqls(
+ `\\frac{dx}{dt} &= x\\notag\\\\x(0) &= 1\\notag`,
+ );
+
+ // don't display initial conditions
+ await updateBooleanInputValue({
+ name: "/showic",
+ boolean: false,
+ core,
+ });
+ stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/ode"].stateValues.latex).eqls(
+ `\\frac{dx}{dt} &= x\\notag`,
+ );
+
+ // display initial conditions again
+ await updateBooleanInputValue({ name: "/showic", boolean: true, core });
+ stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/ode"].stateValues.latex).eqls(
+ `\\frac{dx}{dt} &= x\\notag\\\\x(0) &= 1\\notag`,
+ );
+ });
+
+ it("2D linear system", async () => {
+ let core = await createTestCore({
+ doenetML: `
+ initial condition 1 =
+ initial condition 2 =
+
+ -0.2y
+ 0.1x + 0.3y
+
+
+
+
+ $ode.numericalsolutions{assignNames="f1 f2"}
+
+
+
+
+
+`,
+ });
+
+ let tol = 1e-6;
+ let ic1 = 1;
+ let ic2 = 3;
+ let expectedFx = (t) => 8 * Math.exp(0.1 * t) - 7 * Math.exp(0.2 * t);
+ let expectedFy = (t) => -4 * Math.exp(0.1 * t) + 7 * Math.exp(0.2 * t);
+
+ async function check_items() {
+ let stateVariables = await returnAllStateVariables(core);
+ let ode = stateVariables["/ode"];
+ expect(ode.stateValues.latex).eqls(
+ `\\frac{dx}{dt} &= -0.2 y\\notag\\\\\\frac{dy}{dt} &= 0.1 x + 0.3 y\\notag\\\\x(0) &= ${ic1}\\notag\\\\y(0) &= ${ic2}\\notag`,
+ );
+
+ let solutionFx = createFunctionFromDefinition(
+ ode.stateValues.numericalSolutionFDefinitions[0],
+ );
+ let solutionFy = createFunctionFromDefinition(
+ ode.stateValues.numericalSolutionFDefinitions[1],
+ );
+ let solutionFx2 = createFunctionFromDefinition(
+ stateVariables["/f1"].stateValues.fDefinitions[0],
+ );
+ let solutionFy2 = createFunctionFromDefinition(
+ stateVariables["/f2"].stateValues.fDefinitions[0],
+ );
+ let solutionsFromCoreX = stateVariables["/map1"]
+ .replacements!.map(
+ (child) =>
+ stateVariables[child.componentName].replacements![0],
+ )
+ .map(
+ (grandChild) =>
+ stateVariables[grandChild.componentName].stateValues
+ .value,
+ )
+ .map((v) => v.tree);
+ let solutionsFromCoreY = stateVariables["/map1"]
+ .replacements!.map(
+ (child) =>
+ stateVariables[child.componentName].replacements![1],
+ )
+ .map(
+ (grandChild) =>
+ stateVariables[grandChild.componentName].stateValues
+ .value,
+ )
+ .map((v) => v.tree);
+
+ for (let t = 0; t <= 10; t += 1) {
+ expect(solutionFx(t)).closeTo(
+ expectedFx(t),
+ tol * Math.max(1, Math.abs(expectedFx(t))),
+ );
+ expect(solutionFy(t)).closeTo(
+ expectedFy(t),
+ tol * Math.max(1, Math.abs(expectedFy(t))),
+ );
+ expect(solutionFx2(t)).eq(solutionFx(t));
+ expect(solutionFy2(t)).eq(solutionFy(t));
+ expect(solutionsFromCoreX[t]).eq(solutionFx(t));
+ expect(solutionsFromCoreY[t]).eq(solutionFy(t));
+ }
+ }
+
+ await check_items();
+
+ // Change initial condition
+ ic1 = 3;
+ ic2 = -1;
+ expectedFx = (t) => 4 * Math.exp(0.1 * t) - 1 * Math.exp(0.2 * t);
+ expectedFy = (t) => -2 * Math.exp(0.1 * t) + 1 * Math.exp(0.2 * t);
+ await updateMathInputValue({ name: "/ic1", latex: `${ic1}`, core });
+ await updateMathInputValue({ name: "/ic2", latex: `${ic2}`, core });
+ await check_items();
+
+ // Change ic with point
+ ic1 = -5;
+ ic2 = 2;
+ expectedFx = (t) => -6 * Math.exp(0.1 * t) + 1 * Math.exp(0.2 * t);
+ expectedFy = (t) => 3 * Math.exp(0.1 * t) - 1 * Math.exp(0.2 * t);
+ await movePoint({ name: "/point1", x: ic1, y: ic2, core });
+ await check_items();
+
+ // Change initial condition to zero
+ ic1 = 0;
+ ic2 = 0;
+ expectedFx = (t) => 0;
+ expectedFy = (t) => 0;
+ await updateMathInputValue({ name: "/ic1", latex: `${ic1}`, core });
+ await updateMathInputValue({ name: "/ic2", latex: `${ic2}`, core });
+ await check_items();
+ });
+
+ it("higher dimensional ode", async () => {
+ const rightHandSides = ["q", "r", "s", "u", "v", "w"];
+ const initialConditions = ["a", "b", "c", "d", "e", "f"];
+
+ async function check_ode_latex({
+ doenetML,
+ varNames,
+ }: {
+ doenetML: string;
+ varNames: string[];
+ }) {
+ let odeLatex = "";
+ for (let i = 0; i < varNames.length; i++) {
+ odeLatex += `\\frac{d${varNames[i]}}{dt} &= ${rightHandSides[i]}\\notag\\\\`;
+ }
+ for (let i = 0; i < varNames.length; i++) {
+ odeLatex += `${varNames[i]}(0) &= ${initialConditions[i]}\\notag\\\\`;
+ }
+ odeLatex = odeLatex.substring(0, odeLatex.length - 2); // remove ending "\\"
+
+ let core = await createTestCore({ doenetML });
+ let stateVariables = await returnAllStateVariables(core);
+ expect(stateVariables["/ode"].stateValues.latex).eqls(odeLatex);
+ }
+
+ // No variables specified
+ let doenetML = `
+
+q
+r
+s
+u
+v
+w
+
+ `;
+ let varNames = ["x_{1}", "x_{2}", "x_{3}", "x_{4}", "x_{5}", "x_{6}"];
+ await check_ode_latex({ doenetML, varNames });
+
+ // all variables specified
+ doenetML = `
+
+q
+r
+s
+u
+v
+w
+
+ `;
+ varNames = ["j", "k", "l", "m", "n", "p"];
+ await check_ode_latex({ doenetML, varNames });
+
+ // some variables specified
+ doenetML = `
+
+q
+r
+s
+u
+v
+w
+
+ `;
+ varNames = ["j", "k", "l", "x_{4}", "x_{5}", "x_{6}"];
+ await check_ode_latex({ doenetML, varNames });
+ });
+
+ it("copy righthandside, initial conditions", async () => {
+ let core = await createTestCore({
+ doenetML: `
+
+ a*x*y+z
+ x/y
+
+
+ RHS1: $ode.rhs1{name="rhs1a"}
+ RHS2: $ode.rhs2{name="rhs2a"}
+ RHS1: $ode.rhs{name="rhs1b"}
+ Both RHSs: $ode.rhss{name="rhssa"}
+
+ RHS1: $ode.righthandside1{name="rhs1c"}
+ RHS2: $ode.righthandside2{name="rhs2b"}
+ RHS1: $ode.righthandside{name="rhs1d"}
+ Both RHSs: $ode.righthandsides{name="rhssb"}
+
+ IC1: $ode.initialcondition1{name="ic1a"}
+ IC2: $ode.initialcondition2{name="ic2a"}
+ IC1: $ode.initialcondition{name="ic1b"}
+ Both ICs: $ode.initialconditions{name="icsa"}
+
+ Swap right hand sides and keep initial conditions
+
+
+ $ode.rhs2
+ $ode.rhs1
+
+`,
+ });
+
+ let stateVariables = await returnAllStateVariables(core);
+ let rhs1tree = ["+", ["*", "a", "x", "y"], "z"];
+ let rhs2tree = ["/", "x", "y"];
+
+ function expectReplacement(
+ origName: string,
+ repNum: number,
+ desiredValue: any,
+ ) {
+ expect(
+ stateVariables[
+ stateVariables[origName].replacements![repNum].componentName
+ ].stateValues.value.tree,
+ ).eqls(desiredValue);
+ }
+
+ expectReplacement("/rhs1a", 0, rhs1tree);
+ expectReplacement("/rhs2a", 0, rhs2tree);
+ expectReplacement("/rhs1b", 0, rhs1tree);
+ expectReplacement("/rhssa", 0, rhs1tree);
+ expectReplacement("/rhssa", 1, rhs2tree);
+
+ expectReplacement("/rhs1c", 0, rhs1tree);
+ expectReplacement("/rhs2b", 0, rhs2tree);
+ expectReplacement("/rhs1d", 0, rhs1tree);
+ expectReplacement("/rhssb", 0, rhs1tree);
+ expectReplacement("/rhssb", 1, rhs2tree);
+
+ expectReplacement("/ic1a", 0, "c");
+ expectReplacement("/ic2a", 0, 3);
+ expectReplacement("/ic1b", 0, "c");
+ expectReplacement("/icsa", 0, "c");
+ expectReplacement("/icsa", 1, 3);
+
+ let swapLatex = "";
+ swapLatex += "\\frac{dx}{dt} &= \\frac{x}{y}\\notag\\\\";
+ swapLatex += "\\frac{dy}{dt} &= a x y + z\\notag\\\\";
+ swapLatex += "x(0) &= c\\notag\\\\";
+ swapLatex += "y(0) &= 3\\notag";
+ expect(stateVariables["/odeswap"].stateValues.latex).eqls(swapLatex);
+ });
+
+ it("warnings", async () => {
+ let core = await createTestCore({
+ doenetML: `
+a
+
+ 5y
+
+
+
+ 5y
+
+
+
+ 5y
+
+
+
+ 5x
+ 3x
+
+`,
+ });
+
+ let errorWarnings = core.errorWarnings;
+
+ expect(errorWarnings.errors.length).eq(0);
+ expect(errorWarnings.warnings.length).eq(4);
+
+ expect(errorWarnings.warnings[0].message).contain(
+ `Invalid value of a variable: sin(x)`,
+ );
+ expect(errorWarnings.warnings[0].level).eq(1);
+ expect(errorWarnings.warnings[0].doenetMLrange.lineBegin).eq(7);
+ expect(errorWarnings.warnings[0].doenetMLrange.charBegin).eq(47);
+ expect(errorWarnings.warnings[0].doenetMLrange.lineEnd).eq(7);
+ expect(errorWarnings.warnings[0].doenetMLrange.charEnd).eq(52);
+
+ expect(errorWarnings.warnings[1].message).contain(
+ `Variables of must be different than independent variable`,
+ );
+ expect(errorWarnings.warnings[1].level).eq(1);
+ expect(errorWarnings.warnings[1].doenetMLrange.lineBegin).eq(3);
+ expect(errorWarnings.warnings[1].doenetMLrange.charBegin).eq(1);
+ expect(errorWarnings.warnings[1].doenetMLrange.lineEnd).eq(5);
+ expect(errorWarnings.warnings[1].doenetMLrange.charEnd).eq(12);
+
+ expect(errorWarnings.warnings[2].message).contain(
+ `Invalid value of a variable: sin(y)`,
+ );
+ expect(errorWarnings.warnings[2].level).eq(1);
+ expect(errorWarnings.warnings[2].doenetMLrange.lineBegin).eq(11);
+ expect(errorWarnings.warnings[2].doenetMLrange.charBegin).eq(23);
+ expect(errorWarnings.warnings[2].doenetMLrange.lineEnd).eq(11);
+ expect(errorWarnings.warnings[2].doenetMLrange.charEnd).eq(28);
+
+ expect(errorWarnings.warnings[3].message).contain(
+ `Can't define ODE RHS functions with duplicate dependent variable names`,
+ );
+ expect(errorWarnings.warnings[3].level).eq(1);
+ expect(errorWarnings.warnings[3].doenetMLrange.lineBegin).eq(15);
+ expect(errorWarnings.warnings[3].doenetMLrange.charBegin).eq(1);
+ expect(errorWarnings.warnings[3].doenetMLrange.lineEnd).eq(18);
+ expect(errorWarnings.warnings[3].doenetMLrange.charEnd).eq(12);
+ });
+});
diff --git a/packages/test-cypress/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js b/packages/test-cypress/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js
index e7d4c3bf6..71e057352 100644
--- a/packages/test-cypress/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js
+++ b/packages/test-cypress/cypress/e2e/dynamicalsystem/cobwebpolyline.cy.js
@@ -6,1851 +6,6 @@ describe("CobwebPolyline Tag Tests", function () {
cy.visit("/");
});
- it("logistic system", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
- 1/3*x*(3-x)+x
- 1
-
-
-
-
-
-
-
-
- Initial condition is x_0 = 1:
-
-
- $P1.coords =
-
-
-
-
-
-
-
-
-
-
-
-
- x_n
- x_{n+1}
-
-
-
-
-
- Result of cobweb sketch
-
-
-
-
-
-
-
- Cobweb at least three iterations
-
- true
-
- $(graph1/cobweb.vertices)
-
-
-
-
- Submitted responses are the vertices of the polyline:
-
- Current responses are the vertices of the polyline:
-
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- let xCenter = (-2 + 5) / 2,
- yCenter = (-2.2 + 4.5) / 2;
-
- cy.get(cesc("#\\/_p1")).should("contain.text", "Initial condition is");
-
- cy.log("Click both submit buttons");
- cy.get(cesc("#\\/check_initial_submit")).click();
- cy.get(cesc("#\\/check_initial_incorrect")).should("be.visible");
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_incorrect")).should("be.visible");
-
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=−1.5");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(1).should("not.exist");
-
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(−1.5,0)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(2).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(−1.5,0)");
- });
- cy.get(cesc("#\\/cr2")).should("not.exist");
-
- cy.log("Move first point");
-
- cy.window().then(async (win) => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 0: [1, 0] },
- sourceDetails: { vertex: 0 },
- },
- });
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow").should(
- "contain.text",
- "(1,0)",
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_initial_submit")).click();
- cy.get(cesc("#\\/check_initial_correct")).should("be.visible");
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(1).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(−1.5,0)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(2).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2")).should("not.exist");
-
- cy.log("Add second point");
-
- cy.get(cesc("#\\/addline_button")).click();
-
- cy.get(cesc("#\\/cr2") + " .mjx-mrow").should(
- "contain.text",
- `(${xCenter},${yCenter})`,
- );
-
- cy.log("Move second point to wrong location");
-
- cy.window().then(async (win) => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 1: [3, 4] },
- sourceDetails: { vertex: 1 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr2") + " .mjx-mrow").should(
- "contain.text",
- "(3,4)",
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_incorrect")).should("be.visible");
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=4");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(2).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(3,4)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(4).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(3,4)");
- });
- cy.get(cesc("#\\/cr3")).should("not.exist");
-
- cy.log("Move second point to second wrong location");
-
- // Note: move to second wrong point to make sure submit button reappears
- cy.window().then(async (win) => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 1: [1, 1] },
- sourceDetails: { vertex: 1 },
- },
- });
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow").should(
- "contain.text",
- "(1,1)",
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_incorrect")).should("be.visible");
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(2).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(4).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1)");
- });
- cy.get(cesc("#\\/cr3")).should("not.exist");
-
- cy.log("Move second point to correct location");
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 1: [1, 1.6] },
- sourceDetails: { vertex: 1 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr2") + " .mjx-mrow").should(
- "contain.text",
- "(1,1.6667)",
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("20% correct");
- });
-
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(2).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(4).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3")).should("not.exist");
-
- cy.log("Add third point");
-
- // don't move to check that it is at center of graph
- cy.get(cesc("#\\/addline_button")).click();
-
- cy.get(cesc("#\\/cr3") + " .mjx-mrow").should(
- "contain.text",
- `(${xCenter},${yCenter})`,
- );
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "20%",
- );
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("20% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(2).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(${xCenter},${yCenter})`);
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(6).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(${xCenter},${yCenter})`);
- });
- cy.get(cesc("#\\/cr4")).should("not.exist");
-
- cy.log("Move third point to correct location");
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 2: [1.6, 1.6] },
- sourceDetails: { vertex: 2 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr3") + " .mjx-mrow").should(
- "contain.text",
- `(1.6667,1.6667)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "40%",
- );
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("40% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(2).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(6).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4")).should("not.exist");
-
- cy.log("Add fourth point and move to wrong location");
-
- cy.get(cesc("#\\/addline_button")).click();
-
- cy.get(cesc("#\\/cr4") + " .mjx-mrow").should(
- "contain.text",
- `(${xCenter},${yCenter})`,
- );
-
- cy.window().then(async (win) => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 3: [1, 2] },
- sourceDetails: { vertex: 3 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr4") + " .mjx-mrow").should(
- "contain.text",
- `(1,2)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "40%",
- );
-
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("40% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(3).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,2)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(8).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1,2)`);
- });
- cy.get(cesc("#\\/cr5")).should("not.exist");
-
- cy.log("Move fourth point to correct location");
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 3: [1.6, 2.4] },
- sourceDetails: { vertex: 3 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr4") + " .mjx-mrow").should(
- "contain.text",
- `(1.6667,2.4074)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "60%",
- );
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("60% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2.4074");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(3).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,2.4074)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(8).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,2.4074)`);
- });
- cy.get(cesc("#\\/cr5")).should("not.exist");
-
- cy.log("Delete fourth point");
- cy.get(cesc("#\\/deleteline_button")).click();
-
- cy.get(cesc("#\\/cr4")).should("not.exist");
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "40%",
- );
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("40% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(2).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(6).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4")).should("not.exist");
-
- cy.log("Add fourth point back");
- cy.get(cesc("#\\/addline_button")).click();
-
- cy.get(cesc("#\\/cr4") + " .mjx-mrow").should(
- "contain.text",
- `(1.6667,2.4074)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "60%",
- );
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("60% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2.4074");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(3).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,2.4074)");
- });
- cy.get(cesc("#\\/psr")).find(".mjx-mrow").eq(8).should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,2.4074)`);
- });
- cy.get(cesc("#\\/cr5")).should("not.exist");
-
- cy.log("Add fifth point and move to correct location");
-
- cy.get(cesc("#\\/addline_button")).click();
- cy.get(cesc("#\\/cr5") + " .mjx-mrow").should(
- "contain.text",
- `(${xCenter},${yCenter})`,
- );
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 4: [2.4, 2.4] },
- sourceDetails: { vertex: 4 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr5") + " .mjx-mrow").should(
- "contain.text",
- `(2.4074,2.4074)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "80%",
- );
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("80% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2.4074");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(3).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(8)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(10)
- .should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,2.4074)`);
- });
- cy.get(cesc("#\\/cr5") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.4074)`);
- });
- cy.get(cesc("#\\/cr6")).should("not.exist");
-
- cy.log("Add sixth point and move to wrong location");
-
- cy.get(cesc("#\\/addline_button")).click();
- cy.get(cesc("#\\/cr6") + " .mjx-mrow").should(
- "contain.text",
- `(${xCenter},${yCenter})`,
- );
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 5: [-1, 3] },
- sourceDetails: { vertex: 5 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr6") + " .mjx-mrow").should(
- "contain.text",
- `(−1,3)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "80%",
- );
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("80% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2.4074");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(3)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x3=3");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(4).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(8)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(10)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(−1,3)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(12)
- .should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,2.4074)`);
- });
- cy.get(cesc("#\\/cr5") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.4074)`);
- });
- cy.get(cesc("#\\/cr6") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(−1,3)`);
- });
- cy.get(cesc("#\\/cr7")).should("not.exist");
-
- cy.log("Move sixth point correct location");
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 5: [2.4, 3] },
- sourceDetails: { vertex: 5 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr6") + " .mjx-mrow").should(
- "contain.text",
- `(2.4074,2.8829)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_correct")).should("be.visible");
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2.4074");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(3)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x3=2.8829");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(4).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(8)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(10)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.8829)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(12)
- .should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,2.4074)`);
- });
- cy.get(cesc("#\\/cr5") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.4074)`);
- });
- cy.get(cesc("#\\/cr6") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.8829)`);
- });
- cy.get(cesc("#\\/cr7")).should("not.exist");
-
- cy.log("Add seventh point and move to wrong location");
-
- cy.get(cesc("#\\/addline_button")).click();
- cy.get(cesc("#\\/cr7") + " .mjx-mrow").should(
- "contain.text",
- `(${xCenter},${yCenter})`,
- );
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 6: [3, 1] },
- sourceDetails: { vertex: 6 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr7") + " .mjx-mrow").should(
- "contain.text",
- `(3,1)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_partial")).should(
- "contain.text",
- "83%",
- );
- cy.get(cesc("#\\/check_cobweb_partial"))
- .invoke("text")
- .then((text) => {
- expect(text.trim().toLowerCase()).equal("83% correct");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2.4074");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(3)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x3=2.8829");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(4).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(8)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(10)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.8829)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(12)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(3,1)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(14)
- .should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,2.4074)`);
- });
- cy.get(cesc("#\\/cr5") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.4074)`);
- });
- cy.get(cesc("#\\/cr6") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.8829)`);
- });
- cy.get(cesc("#\\/cr7") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(3,1)`);
- });
- cy.get(cesc("#\\/cr8")).should("not.exist");
-
- cy.log("Move seventh point correct location");
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 6: [3, 3] },
- sourceDetails: { vertex: 6 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr7") + " .mjx-mrow").should(
- "contain.text",
- `(2.8829,2.8829)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_correct")).should("be.visible");
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2.4074");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(3)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x3=2.8829");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(4).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(8)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(10)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.8829)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(12)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.8829,2.8829)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(14)
- .should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,2.4074)`);
- });
- cy.get(cesc("#\\/cr5") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.4074)`);
- });
- cy.get(cesc("#\\/cr6") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.8829)`);
- });
- cy.get(cesc("#\\/cr7") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.8829,2.8829)`);
- });
- cy.get(cesc("#\\/cr8")).should("not.exist");
-
- cy.log("Add eighth point and move to correct location");
-
- cy.get(cesc("#\\/addline_button")).click();
- cy.get(cesc("#\\/cr8") + " .mjx-mrow").should(
- "contain.text",
- `(${xCenter},${yCenter})`,
- );
-
- cy.window().then(async () => {
- win.callAction1({
- actionName: "movePolyline",
- componentName: "/graph1/cobweb",
- args: {
- pointCoords: { 7: [3, 3] },
- sourceDetails: { vertex: 7 },
- },
- });
- });
-
- cy.get(cesc("#\\/cr8") + " .mjx-mrow").should(
- "contain.text",
- `(2.8829,2.9954)`,
- );
-
- cy.log("Click submit");
-
- cy.get(cesc("#\\/check_cobweb_submit")).click();
- cy.get(cesc("#\\/check_cobweb_correct")).should("be.visible");
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x0=1");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(1)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x1=1.6667");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x2=2.4074");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(3)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x3=2.8829");
- });
- cy.get(cesc("#\\/_md1"))
- .find(".mjx-mtr")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x4=2.9954");
- });
- cy.get(cesc("#\\/_md1")).find(".mjx-mtr").eq(5).should("not.exist");
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(2)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(4)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,1.6667)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(6)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1.6667,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(8)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.4074)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(10)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.4074,2.8829)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(12)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.8829,2.8829)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(14)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(2.8829,2.9954)");
- });
- cy.get(cesc("#\\/psr"))
- .find(".mjx-mrow")
- .eq(16)
- .should("not.exist");
-
- cy.get(cesc("#\\/cr1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,0)");
- });
- cy.get(cesc("#\\/cr2") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("(1,1.6667)");
- });
- cy.get(cesc("#\\/cr3") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,1.6667)`);
- });
- cy.get(cesc("#\\/cr4") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(1.6667,2.4074)`);
- });
- cy.get(cesc("#\\/cr5") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.4074)`);
- });
- cy.get(cesc("#\\/cr6") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.4074,2.8829)`);
- });
- cy.get(cesc("#\\/cr7") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.8829,2.8829)`);
- });
- cy.get(cesc("#\\/cr8") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(`(2.8829,2.9954)`);
- });
- cy.get(cesc("#\\/cr9")).should("not.exist");
- });
- });
-
it("cobweb graded applet", () => {
cy.window().then(async (win) => {
win.postMessage(
@@ -2737,75 +892,4 @@ describe("CobwebPolyline Tag Tests", function () {
cy.get(cesc2("#/cobwebTutorial/next_button")).should("be.disabled");
cy.get(cesc2("#/ca")).should("have.text", "1");
});
-
- it("handle bad initial point, lock to solution", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
-
- x^2
-
-
- Initial point:
-
-
-
-
- Vertices: $cobweb.vertices
-
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc2("#/_p1")).should("have.text", "Initial point: ");
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow")
- .eq(0)
- .should("have.text", "(_,0)");
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow")
- .eq(3)
- .should("have.text", "(NaN,NaN)");
-
- cy.get(cesc2("#/x0") + " textarea").type("0.9{enter}", { force: true });
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow").should("contain.text", "(0.9,0)");
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow")
- .eq(0)
- .should("have.text", "(0.9,0)");
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow")
- .eq(2)
- .should("have.text", "(0.9,0.81)");
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow")
- .eq(100)
- .should("have.text", "(0,0)");
-
- cy.get(cesc2("#/x0") + " textarea").type(
- "{end}{backspace}{backspace}{backspace}(1.1,3){enter}",
- {
- force: true,
- },
- );
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow").should("contain.text", "(1.1,3)");
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow")
- .eq(0)
- .should("have.text", "(1.1,3)");
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow")
- .eq(2)
- .should("have.text", "(1.1,1.21)");
-
- cy.get(cesc2("#/_p2") + " .mjx-mrow")
- .eq(100)
- .should("have.text", "(∞,∞)");
- });
});
diff --git a/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumcurve.cy.js b/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumcurve.cy.js
deleted file mode 100644
index 62aae3674..000000000
--- a/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumcurve.cy.js
+++ /dev/null
@@ -1,327 +0,0 @@
-import me from "math-expressions";
-import { cesc } from "@doenet/utils";
-
-describe("Equilibriumcurve Tag Tests", function () {
- beforeEach(() => {
- cy.clearIndexedDB();
- cy.visit("/");
- });
-
- it("equilibriumcurve change stable", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
-
-
-
-
-
-
-
-
-
-
-
- $(g/A.stable{assignNames="gAs"})
- $(g/B.stable{assignNames="gBs"})
- $(g/C.stable{assignNames="gCs"})
- $(g/D.stable{assignNames="gDs"})
-
-
-
- $g{name="g2"}
-
-
- $(g2/A.stable{assignNames="g2As"})
- $(g2/B.stable{assignNames="g2Bs"})
- $(g2/C.stable{assignNames="g2Cs"})
- $(g2/D.stable{assignNames="g2Ds"})
-
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait until loaded
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "false");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(false);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
- expect(
- stateVariables["/g/A"].stateValues.numericalThroughPoints,
- ).eqls([
- [1, 2],
- [3, 4],
- [2, 6],
- ]);
- expect(
- stateVariables["/g/B"].stateValues.numericalThroughPoints,
- ).eqls([
- [3, 2],
- [5, 4],
- [4, 6],
- ]);
- expect(
- stateVariables["/g/C"].stateValues.numericalThroughPoints,
- ).eqls([
- [-3, 2],
- [-5, 4],
- [-4, 6],
- ]);
- expect(
- stateVariables["/g/D"].stateValues.numericalThroughPoints,
- ).eqls([
- [-1, 2],
- [-3, 4],
- [-2, 6],
- ]);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
- expect(
- stateVariables["/g2/A"].stateValues.numericalThroughPoints,
- ).eqls([
- [1, 2],
- [3, 4],
- [2, 6],
- ]);
- expect(
- stateVariables["/g2/B"].stateValues.numericalThroughPoints,
- ).eqls([
- [3, 2],
- [5, 4],
- [4, 6],
- ]);
- expect(
- stateVariables["/g2/C"].stateValues.numericalThroughPoints,
- ).eqls([
- [-3, 2],
- [-5, 4],
- [-4, 6],
- ]);
- expect(
- stateVariables["/g2/D"].stateValues.numericalThroughPoints,
- ).eqls([
- [-1, 2],
- [-3, 4],
- [-2, 6],
- ]);
- });
-
- cy.log("switch C via boolean input");
- cy.get(cesc("#\\/b1")).click();
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
- });
-
- cy.log("switch D via boolean input");
- cy.get(cesc("#\\/b2")).click();
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
- });
-
- cy.log("switch A via first action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchCurve",
- componentName: "/g/A",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(false);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "false");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "false");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("switch A via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchCurve",
- componentName: "/g2/A",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("cannot switch B via action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchCurve",
- componentName: "/g/B",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("cannot switch C via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchCurve",
- componentName: "/g2/C",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("switch D via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchCurve",
- componentName: "/g2/D",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
- });
- });
-});
diff --git a/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumline.cy.js b/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumline.cy.js
deleted file mode 100644
index 59cea66e4..000000000
--- a/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumline.cy.js
+++ /dev/null
@@ -1,311 +0,0 @@
-import me from "math-expressions";
-import { cesc } from "@doenet/utils";
-
-describe("Equilibriumline Tag Tests", function () {
- beforeEach(() => {
- cy.clearIndexedDB();
- cy.visit("/");
- });
-
- it("equilibriumline change stable", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
-
- y=4
- y=7
- y=-9
- y=-3
-
-
-
-
-
-
- $(g/A.stable{assignNames="gAs"})
- $(g/B.stable{assignNames="gBs"})
- $(g/C.stable{assignNames="gCs"})
- $(g/D.stable{assignNames="gDs"})
-
-
-
- $g{name="g2"}
-
-
- $(g2/A.stable{assignNames="g2As"})
- $(g2/B.stable{assignNames="g2Bs"})
- $(g2/C.stable{assignNames="g2Cs"})
- $(g2/D.stable{assignNames="g2Ds"})
-
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait until loaded
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "false");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(false);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
- expect(stateVariables["/g/A"].stateValues.equation).eqls([
- "=",
- "y",
- 4,
- ]);
- expect(stateVariables["/g/B"].stateValues.equation).eqls([
- "=",
- "y",
- 7,
- ]);
- expect(stateVariables["/g/C"].stateValues.equation).eqls([
- "=",
- "y",
- -9,
- ]);
- expect(stateVariables["/g/D"].stateValues.equation).eqls([
- "=",
- "y",
- -3,
- ]);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/A"].stateValues.equation).eqls([
- "=",
- "y",
- 4,
- ]);
- expect(stateVariables["/g2/B"].stateValues.equation).eqls([
- "=",
- "y",
- 7,
- ]);
- expect(stateVariables["/g2/C"].stateValues.equation).eqls([
- "=",
- "y",
- -9,
- ]);
- expect(stateVariables["/g2/D"].stateValues.equation).eqls([
- "=",
- "y",
- -3,
- ]);
- });
-
- cy.log("switch C via boolean input");
- cy.get(cesc("#\\/b1")).click();
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
- });
-
- cy.log("switch D via boolean input");
- cy.get(cesc("#\\/b2")).click();
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
- });
-
- cy.log("switch A via first action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchLine",
- componentName: "/g/A",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(false);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "false");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "false");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("switch A via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchLine",
- componentName: "/g2/A",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("cannot switch B via action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchLine",
- componentName: "/g/B",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("cannot switch C via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchLine",
- componentName: "/g2/C",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("switch D via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchLine",
- componentName: "/g2/D",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
- });
- });
-});
diff --git a/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumpoint.cy.js b/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumpoint.cy.js
deleted file mode 100644
index e5aa9d664..000000000
--- a/packages/test-cypress/cypress/e2e/dynamicalsystem/equilibriumpoint.cy.js
+++ /dev/null
@@ -1,295 +0,0 @@
-import me from "math-expressions";
-import { cesc } from "@doenet/utils";
-
-describe("Equilibriumpoint Tag Tests", function () {
- beforeEach(() => {
- cy.clearIndexedDB();
- cy.visit("/");
- });
-
- it("equilibriumpoint change stable", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
-
- (4,0)
- (7,0)
- (-9,0)
- (-3,0)
-
-
-
-
-
-
- $(g/A.stable{assignNames="gAs"})
- $(g/B.stable{assignNames="gBs"})
- $(g/C.stable{assignNames="gCs"})
- $(g/D.stable{assignNames="gDs"})
-
-
-
- $g{name="g2"}
-
-
- $(g2/A.stable{assignNames="g2As"})
- $(g2/B.stable{assignNames="g2Bs"})
- $(g2/C.stable{assignNames="g2Cs"})
- $(g2/D.stable{assignNames="g2Ds"})
-
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait until loaded
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "false");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(false);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
- expect(stateVariables["/g/A"].stateValues.xs.map((x) => x)).eqls([
- 4, 0,
- ]);
- expect(stateVariables["/g/B"].stateValues.xs.map((x) => x)).eqls([
- 7, 0,
- ]);
- expect(stateVariables["/g/C"].stateValues.xs.map((x) => x)).eqls([
- -9, 0,
- ]);
- expect(stateVariables["/g/D"].stateValues.xs.map((x) => x)).eqls([
- -3, 0,
- ]);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/A"].stateValues.xs.map((x) => x)).eqls([
- 4, 0,
- ]);
- expect(stateVariables["/g2/B"].stateValues.xs.map((x) => x)).eqls([
- 7, 0,
- ]);
- expect(stateVariables["/g2/C"].stateValues.xs.map((x) => x)).eqls([
- -9, 0,
- ]);
- expect(stateVariables["/g2/D"].stateValues.xs.map((x) => x)).eqls([
- -3, 0,
- ]);
- });
-
- cy.log("switch C via boolean input");
- cy.get(cesc("#\\/b1")).click();
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
- });
-
- cy.log("switch D via boolean input");
- cy.get(cesc("#\\/b2")).click();
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
- });
-
- cy.log("switch A via first action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchPoint",
- componentName: "/g/A",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(false);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "false");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "false");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("switch A via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchPoint",
- componentName: "/g2/A",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("cannot switch B via action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchPoint",
- componentName: "/g/B",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("cannot switch C via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchPoint",
- componentName: "/g2/C",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(true);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(true);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "true");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "true");
- });
-
- cy.log("switch D via second action");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "switchPoint",
- componentName: "/g2/D",
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- expect(stateVariables["/g/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g/D"].stateValues.stable).eq(false);
-
- expect(stateVariables["/g2/A"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/B"].stateValues.stable).eq(false);
- expect(stateVariables["/g2/C"].stateValues.stable).eq(true);
- expect(stateVariables["/g2/D"].stateValues.stable).eq(false);
-
- cy.get(cesc("#\\/gAs")).should("have.text", "true");
- cy.get(cesc("#\\/gBs")).should("have.text", "false");
- cy.get(cesc("#\\/gCs")).should("have.text", "true");
- cy.get(cesc("#\\/gDs")).should("have.text", "false");
- cy.get(cesc("#\\/g2As")).should("have.text", "true");
- cy.get(cesc("#\\/g2Bs")).should("have.text", "false");
- cy.get(cesc("#\\/g2Cs")).should("have.text", "true");
- cy.get(cesc("#\\/g2Ds")).should("have.text", "false");
- });
- });
-});
diff --git a/packages/test-cypress/cypress/e2e/dynamicalsystem/odesystem.cy.js b/packages/test-cypress/cypress/e2e/dynamicalsystem/odesystem.cy.js
deleted file mode 100644
index 7f514dba4..000000000
--- a/packages/test-cypress/cypress/e2e/dynamicalsystem/odesystem.cy.js
+++ /dev/null
@@ -1,2029 +0,0 @@
-import { cesc, createFunctionFromDefinition } from "@doenet/utils";
-
-describe("ODEsystem Tag Tests", function () {
- beforeEach(() => {
- cy.clearIndexedDB();
- cy.visit("/");
- });
-
- it("1D linear system", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
- a =
- initial condition =
- tol =
-
- $a x
-
-
-
-
- $ode.numericalsolution{assignNames="f"}
-
-
-
-
-
- 0
- $tol.value{assignNames="tol2"}
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xx(0)=1");
- });
-
- let ic = 1,
- a = 1,
- tol = 1e-6;
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
-
- let expectedF = (x) => ic * Math.exp(a * x);
- for (let x = 0; x <= 5; x += 0.5) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- expect(solutionsFromCore[2 * x]).eq(solutionF(x));
- }
- });
-
- cy.log("Change initial condition");
- cy.get(cesc("#\\/ic") + " textarea").type(`{end}{backspace}3{enter}`, {
- force: true,
- });
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=xx(0)=3",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xx(0)=3");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- ic = 3;
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let expectedF = (x) => ic * Math.exp(a * x);
- for (let x = 0; x <= 5; x += 0.5) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- expect(solutionsFromCore[2 * x]).eq(solutionF(x));
- }
- });
-
- cy.log("Change parameter");
- cy.get(cesc("#\\/a") + " textarea").type(`{end}{backspace}-2{enter}`, {
- force: true,
- });
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=−2xx(0)=3",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.replace("−", "-").trim()).equal("dxdt=-2xx(0)=3");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- a = -2;
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let expectedF = (x) => ic * Math.exp(a * x);
- for (let x = 0; x <= 5; x += 0.5) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- expect(solutionsFromCore[2 * x]).eq(solutionF(x));
- }
- });
-
- cy.log("Change ic with point");
- cy.window().then(async (win) => {
- ic = -5;
-
- await win.callAction1({
- actionName: "movePoint",
- componentName: "/_point1",
- args: { y: ic },
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let expectedF = (x) => ic * Math.exp(a * x);
- for (let x = 0; x <= 5; x += 0.5) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- expect(solutionsFromCore[2 * x]).eq(solutionF(x));
- }
- });
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=−2xx(0)=−5",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.replace(/−/g, "-").trim()).equal("dxdt=-2xx(0)=-5");
- });
-
- cy.log("Change tolerance");
- cy.get(cesc("#\\/tol") + " textarea").type(
- `{ctrl+home}{shift+end}{backspace}1E-10{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/tol2") + " .mjx-mrow").should(
- "contain.text",
- "1⋅10−10",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.replace(/−/g, "-").trim()).equal("dxdt=-2xx(0)=-5");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- tol = 1e-10;
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let expectedF = (x) => ic * Math.exp(a * x);
- for (let x = 0; x <= 5; x += 0.5) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- expect(solutionsFromCore[2 * x]).eq(solutionF(x));
- }
- });
-
- cy.log("Change parameter again");
- cy.get(cesc("#\\/a") + " textarea").type(
- `{end}{backspace}{backspace}0.5{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=0.5xx(0)=−5",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.replace(/−/g, "-").trim()).equal(
- "dxdt=0.5xx(0)=-5",
- );
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- a = 0.5;
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let expectedF = (x) => ic * Math.exp(a * x);
- for (let x = 0; x <= 5; x += 0.5) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- expect(solutionsFromCore[2 * x]).eq(solutionF(x));
- }
- });
-
- cy.log("Change initial condition to zero");
- cy.get(cesc("#\\/ic") + " textarea").type(
- `{end}{backspace}{backspace}0{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=0.5xx(0)=0",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.replace(/−/g, "-").trim()).equal("dxdt=0.5xx(0)=0");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- for (let x = 0; x <= 1000; x += 100) {
- expect(solutionF(x)).eq(0);
- }
- for (let x = 0; x <= 5; x += 0.5) {
- expect(solutionsFromCore[2 * x]).eq(0);
- }
- });
- });
-
- it("effect of max iterations, chunksize", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
- tol =
- T =
- maxiter =
- chunksize =
-
- x
-
-
- f($T) = $$(ode.numericalSolution)($T)
-
-
-
- $tol.value{assignNames="tol2"}
- $T.value{assignNames="T2"}
- $maxiter.value{assignNames="maxiter2"}
- $chunksize.value{assignNames="chunksize2"}
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- let tol = 1e-6;
- let expectedF = (x) => Math.exp(x);
-
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(Number(text.split("=")[1])).closeTo(
- expectedF(10),
- tol * expectedF(10),
- );
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- for (let x = 0; x <= 10; x += 1) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- }
- });
-
- cy.log("Can't make it to t=20");
- cy.get(cesc("#\\/T") + " textarea").type(
- `{end}{backspace}{backspace}20{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/T2") + " .mjx-mrow").should("contain.text", "20");
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.split("=")[1].trim()).eq("NaN");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- assert.isNaN(solutionF(20));
- });
-
- cy.log("increase maxiterations");
- cy.get(cesc("#\\/maxiter") + " textarea").type(
- `{ctrl+home}{shift+end}{backspace}2000{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/maxiter2") + " .mjx-mrow").should(
- "contain.text",
- "2000",
- );
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(Number(text.split("=")[1])).closeTo(
- expectedF(20),
- tol * expectedF(20),
- );
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- for (let x = 0; x <= 20; x += 1) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- }
- });
-
- cy.log("Can't make it if decrease tolerance");
- cy.get(cesc("#\\/tol") + " textarea").type(
- `{ctrl+home}{shift+end}{backspace}1E-8{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/tol2") + " .mjx-mrow").should(
- "contain.text",
- "1⋅10−8",
- );
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.split("=")[1].trim()).eq("NaN");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- assert.isNaN(solutionF(20));
- });
-
- cy.log("increase maxiterations further");
- cy.get(cesc("#\\/maxiter") + " textarea").type(
- `{ctrl+home}{shift+end}{backspace}5000{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/maxiter2") + " .mjx-mrow").should(
- "contain.text",
- "5000",
- );
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(Number(text.split("=")[1])).closeTo(
- expectedF(20),
- tol * expectedF(20),
- );
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- for (let x = 0; x <= 20; x += 1) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- }
- });
-
- cy.log("decrease maxiterations back down");
- cy.get(cesc("#\\/maxiter") + " textarea").type(
- `{ctrl+home}{shift+end}{backspace}1000{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/maxiter2") + " .mjx-mrow").should(
- "contain.text",
- "1000",
- );
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.split("=")[1].trim()).eq("NaN");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- assert.isNaN(solutionF(20));
- });
-
- cy.log("decrease chunksize");
- cy.get(cesc("#\\/chunksize") + " textarea").type(
- `{end}{backspace}{backspace}1{enter}`,
- { force: true },
- );
-
- cy.get(cesc("#\\/chunksize2") + " .mjx-mrow").should(
- "not.contain.text",
- "10",
- );
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(Number(text.split("=")[1])).closeTo(
- expectedF(20),
- tol * expectedF(20),
- );
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- for (let x = 0; x <= 20; x += 1) {
- expect(solutionF(x)).closeTo(
- expectedF(x),
- tol * Math.max(1, Math.abs(expectedF(x))),
- );
- }
- });
- });
-
- it("change variables 1D", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
- independent variable =
- dependent variable =
-
-
- $dvar
-
-
-
- $ode.numericalsolution{assignNames="f"}
-
-
-
-
-
- $ivar.value{assignNames="ivar2"}
- $dvar.value{assignNames="dvar2"}
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- let tol = 1e-6;
- let expectedF = (x) => Math.exp(x);
-
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xx(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
-
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- expect(solutionF(t)).closeTo(
- expectedF(t),
- tol * Math.max(1, Math.abs(expectedF(t))),
- );
- expect(solutionsFromCore[t]).eq(solutionF(t));
- }
- });
-
- cy.log("change independent variable");
- cy.get(cesc("#\\/ivar") + " textarea").type(
- `{end}{backspace}s{enter}`,
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/ivar2") + " .mjx-mrow").should("contain.text", "s");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxds=xx(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
-
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- expect(solutionF(t)).closeTo(
- expectedF(t),
- tol * Math.max(1, Math.abs(expectedF(t))),
- );
- expect(solutionsFromCore[t]).eq(solutionF(t));
- }
- });
-
- cy.log("erase independent variable");
- cy.get(cesc("#\\/ivar") + " textarea").type("{end}{backspace}{enter}", {
- force: true,
- });
-
- cy.get(cesc("#\\/ivar2") + " .mjx-mrow").should("contain.text", "_");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxd_=xx(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- assert.isNaN(solutionF(t));
- assert.isNaN(solutionsFromCore[t]);
- }
- });
-
- cy.log("restore independent variable");
- cy.get(cesc("#\\/ivar") + " textarea").type(
- "{end}{backspace}u{enter}",
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/ivar2") + " .mjx-mrow").should("contain.text", "u");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdu=xx(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- expect(solutionF(t)).closeTo(
- expectedF(t),
- tol * Math.max(1, Math.abs(expectedF(t))),
- );
- expect(solutionsFromCore[t]).eq(solutionF(t));
- }
- });
-
- cy.log("invalid independent variable");
- cy.get(cesc("#\\/ivar") + " textarea").type(
- "{end}{backspace}1{enter}",
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/ivar2") + " .mjx-mrow").should("contain.text", "1");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxd1=xx(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- assert.isNaN(solutionF(t));
- assert.isNaN(solutionsFromCore[t]);
- }
- });
-
- cy.log("restore independent variable");
- cy.get(cesc("#\\/ivar") + " textarea").type(
- "{end}{backspace}v{enter}",
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/ivar2") + " .mjx-mrow").should("contain.text", "v");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdv=xx(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- expect(solutionF(t)).closeTo(
- expectedF(t),
- tol * Math.max(1, Math.abs(expectedF(t))),
- );
- expect(solutionsFromCore[t]).eq(solutionF(t));
- }
- });
-
- cy.log("change dependent variable");
- cy.get(cesc("#\\/dvar") + " textarea").type(
- "{end}{backspace}z{enter}",
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/dvar2") + " .mjx-mrow").should("contain.text", "z");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dzdv=zz(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- expect(solutionF(t)).closeTo(
- expectedF(t),
- tol * Math.max(1, Math.abs(expectedF(t))),
- );
- expect(solutionsFromCore[t]).eq(solutionF(t));
- }
- });
-
- cy.log("duplicate variable");
- cy.get(cesc("#\\/dvar") + " textarea").type(
- "{end}{backspace}v{enter}",
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/dvar2") + " .mjx-mrow").should("contain.text", "v");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dvdv=vv(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- assert.isNaN(solutionF(t));
- assert.isNaN(solutionsFromCore[t]);
- }
- });
-
- cy.log("different dependent variable");
- cy.get(cesc("#\\/dvar") + " textarea").type(
- "{end}{backspace}v_1{enter}",
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/dvar2") + " .mjx-mrow").should("contain.text", "v1");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dv1dv=v1v1(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- expect(solutionF(t)).closeTo(
- expectedF(t),
- tol * Math.max(1, Math.abs(expectedF(t))),
- );
- expect(solutionsFromCore[t]).eq(solutionF(t));
- }
- });
-
- cy.log("invalid dependent variable");
- cy.get(cesc("#\\/dvar") + " textarea").type(
- "{ctrl+home}{shift+end}{backspace}ab{enter}",
- { force: true },
- );
-
- cy.get(cesc("#\\/dvar2") + " .mjx-mrow").should("contain.text", "ab");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dabdv=abab(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- assert.isNaN(solutionF(t));
- assert.isNaN(solutionsFromCore[t]);
- }
- });
-
- cy.log("restore dependent variable");
- cy.get(cesc("#\\/dvar") + " textarea").type(
- "{end}{backspace}{backspace}a{enter}",
- { force: true },
- );
-
- cy.get(cesc("#\\/dvar2") + " .mjx-mrow").should(
- "not.contain.text",
- "ab",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dadv=aa(0)=1");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let solutionF = createFunctionFromDefinition(
- stateVariables["/ode"].stateValues
- .numericalSolutionFDefinitions[0],
- );
- let solutionsFromCore = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- expect(solutionF(0)).eq(1);
- expect(solutionsFromCore[0]).eq(1);
- for (let t = 1; t <= 5; t += 1) {
- expect(solutionF(t)).closeTo(
- expectedF(t),
- tol * Math.max(1, Math.abs(expectedF(t))),
- );
- expect(solutionsFromCore[t]).eq(solutionF(t));
- }
- });
- });
-
- it("display digits", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
- displaydigits =
-
-
- 0.123456789123456789x
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=0.1234567891xx(0)=9.87654322");
- });
-
- cy.log("change display digits");
- cy.get(cesc("#\\/digits") + " textarea").type(
- "{end}{backspace}{backspace}2{enter}",
- { force: true },
- );
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=0.12xx(0)=9.9",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=0.12xx(0)=9.9");
- });
-
- cy.log("change display digits again");
- cy.get(cesc("#\\/digits") + " textarea").type(
- "{end}{backspace}14{enter}",
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=0.12345678912346xx(0)=9.8765432198765",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(
- "dxdt=0.12345678912346xx(0)=9.8765432198765",
- );
- });
- });
-
- it("initial independent variable value", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
- initial t =
- final t =
-
-
- x
-
-
- We started with
- x($ode.initialindependentvariablevalue) = 1.
-
- We end with
- x($tf) = $$(ode.numericalSolution)($tf)
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xx(0)=1");
- });
-
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x(0)=1");
- });
-
- cy.get(cesc("#\\/_m2"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.split("=")[0].trim()).equal("x(10)");
- expect(Number(text.split("=")[1])).closeTo(
- Math.exp(10),
- 1e-6 * Math.exp(10),
- );
- });
-
- cy.log("Change initial time");
- cy.get(cesc("#\\/t0") + " textarea").type("{end}{backspace}-5{enter}", {
- force: true,
- });
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=xx(−5)=1",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xx(−5)=1");
- });
-
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x(−5)=1");
- });
-
- cy.get(cesc("#\\/_m2"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.split("=")[0].trim()).equal("x(10)");
- expect(Number(text.split("=")[1])).closeTo(
- Math.exp(15),
- 1e-6 * Math.exp(15),
- );
- });
-
- cy.log("Change initial and final time");
- cy.get(cesc("#\\/tf") + " textarea").type(
- "{end}{backspace}{backspace}12{enter}",
- { force: true },
- );
- cy.get(cesc("#\\/t0") + " textarea").type(
- "{end}{backspace}{backspace}11{enter}",
- { force: true },
- );
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=xx(11)=1",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xx(11)=1");
- });
-
- cy.get(cesc("#\\/_m1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("x(11)=1");
- });
-
- cy.get(cesc("#\\/_m2"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.split("=")[0].trim()).equal("x(12)");
- expect(Number(text.split("=")[1])).closeTo(
- Math.exp(1),
- 1e-6 * Math.exp(1),
- );
- });
- });
-
- it("display initial conditions", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
- display initial conditions:
-
- x
-
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xx(0)=1");
- });
-
- cy.log("don't display initial conditions");
- cy.get(cesc("#\\/showic")).click();
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should("contain.text", "dxdt=x");
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=x");
- });
-
- cy.log("display initial conditions again");
- cy.get(cesc("#\\/showic")).click();
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=xx(0)=1",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xx(0)=1");
- });
- });
-
- it("2D linear system", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
- initial condition 1 =
- initial condition 2 =
-
- -0.2y
- 0.1x + 0.3y
-
-
-
-
- $ode.numericalsolutions{assignNames="f1 f2"}
-
-
-
-
-
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- let tol = 1e-6;
-
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim().replace(/−/g, "-")).equal(
- "dxdt=-0.2ydydt=0.1x+0.3yx(0)=1y(0)=3",
- );
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let ode = stateVariables["/ode"];
- let solutionFx = createFunctionFromDefinition(
- ode.stateValues.numericalSolutionFDefinitions[0],
- );
- let solutionFy = createFunctionFromDefinition(
- ode.stateValues.numericalSolutionFDefinitions[1],
- );
- let solutionFx2 = createFunctionFromDefinition(
- stateVariables["/f1"].stateValues.fDefinitions[0],
- );
- let solutionFy2 = createFunctionFromDefinition(
- stateVariables["/f2"].stateValues.fDefinitions[0],
- );
- let solutionsFromCoreX = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let solutionsFromCoreY = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[1]
- .componentName
- ].stateValues.value,
- );
- let expectedFx = (t) =>
- 8 * Math.exp(0.1 * t) - 7 * Math.exp(0.2 * t);
- let expectedFy = (t) =>
- -4 * Math.exp(0.1 * t) + 7 * Math.exp(0.2 * t);
- for (let t = 0; t <= 10; t += 1) {
- expect(solutionFx(t)).closeTo(
- expectedFx(t),
- tol * Math.max(1, Math.abs(expectedFx(t))),
- );
- expect(solutionFy(t)).closeTo(
- expectedFy(t),
- tol * Math.max(1, Math.abs(expectedFy(t))),
- );
- expect(solutionFx2(t)).eq(solutionFx(t));
- expect(solutionFy2(t)).eq(solutionFy(t));
- expect(solutionsFromCoreX[t]).eq(solutionFx(t));
- expect(solutionsFromCoreY[t]).eq(solutionFy(t));
- }
- });
-
- cy.log("Change initial condition");
- cy.get(cesc("#\\/ic1") + " textarea").type(`{end}{backspace}3{enter}`, {
- force: true,
- });
- cy.get(cesc("#\\/ic2") + " textarea").type(
- `{end}{backspace}-1{enter}`,
- {
- force: true,
- },
- );
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=−0.2ydydt=0.1x+0.3yx(0)=3y(0)=−1",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim().replace(/−/g, "-")).equal(
- "dxdt=-0.2ydydt=0.1x+0.3yx(0)=3y(0)=-1",
- );
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let ode = stateVariables["/ode"];
- let solutionFx = createFunctionFromDefinition(
- ode.stateValues.numericalSolutionFDefinitions[0],
- );
- let solutionFy = createFunctionFromDefinition(
- ode.stateValues.numericalSolutionFDefinitions[1],
- );
- let solutionFx2 = createFunctionFromDefinition(
- stateVariables["/f1"].stateValues.fDefinitions[0],
- );
- let solutionFy2 = createFunctionFromDefinition(
- stateVariables["/f2"].stateValues.fDefinitions[0],
- );
- let solutionsFromCoreX = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let solutionsFromCoreY = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[1]
- .componentName
- ].stateValues.value,
- );
- let expectedFx = (t) =>
- 4 * Math.exp(0.1 * t) - 1 * Math.exp(0.2 * t);
- let expectedFy = (t) =>
- -2 * Math.exp(0.1 * t) + 1 * Math.exp(0.2 * t);
- for (let t = 0; t <= 10; t += 1) {
- expect(solutionFx(t)).closeTo(
- expectedFx(t),
- tol * Math.max(1, Math.abs(expectedFx(t))),
- );
- expect(solutionFy(t)).closeTo(
- expectedFy(t),
- tol * Math.max(1, Math.abs(expectedFy(t))),
- );
- expect(solutionFx2(t)).eq(solutionFx(t));
- expect(solutionFy2(t)).eq(solutionFy(t));
- expect(solutionsFromCoreX[t]).eq(solutionFx(t));
- expect(solutionsFromCoreY[t]).eq(solutionFy(t));
- }
- });
-
- cy.log("Change ic with point");
- cy.window().then(async (win) => {
- await win.callAction1({
- actionName: "movePoint",
- componentName: "/_point1",
- args: { x: -5, y: 2 },
- });
-
- let stateVariables = await win.returnAllStateVariables1();
-
- let ode = stateVariables["/ode"];
- let solutionFx = createFunctionFromDefinition(
- ode.stateValues.numericalSolutionFDefinitions[0],
- );
- let solutionFy = createFunctionFromDefinition(
- ode.stateValues.numericalSolutionFDefinitions[1],
- );
- let solutionFx2 = createFunctionFromDefinition(
- stateVariables["/f1"].stateValues.fDefinitions[0],
- );
- let solutionFy2 = createFunctionFromDefinition(
- stateVariables["/f2"].stateValues.fDefinitions[0],
- );
- let solutionsFromCoreX = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let solutionsFromCoreY = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[1]
- .componentName
- ].stateValues.value,
- );
- let expectedFx = (t) =>
- -6 * Math.exp(0.1 * t) + 1 * Math.exp(0.2 * t);
- let expectedFy = (t) =>
- 3 * Math.exp(0.1 * t) - 1 * Math.exp(0.2 * t);
- for (let t = 0; t <= 10; t += 1) {
- expect(solutionFx(t)).closeTo(
- expectedFx(t),
- tol * Math.max(1, Math.abs(expectedFx(t))),
- );
- expect(solutionFy(t)).closeTo(
- expectedFy(t),
- tol * Math.max(1, Math.abs(expectedFy(t))),
- );
- expect(solutionFx2(t)).eq(solutionFx(t));
- expect(solutionFy2(t)).eq(solutionFy(t));
- expect(solutionsFromCoreX[t]).eq(solutionFx(t));
- expect(solutionsFromCoreY[t]).eq(solutionFy(t));
- }
- });
-
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim().replace(/−/g, "-")).equal(
- "dxdt=-0.2ydydt=0.1x+0.3yx(0)=-5y(0)=2",
- );
- });
-
- cy.log("Change initial condition to zero");
- cy.get(cesc("#\\/ic1") + " textarea").type(
- `{end}{backspace}{backspace}0{enter}`,
- { force: true },
- );
- cy.get(cesc("#\\/ic2") + " textarea").type(`{end}{backspace}0{enter}`, {
- force: true,
- });
-
- cy.get(cesc("#\\/ode") + " .mjx-mrow").should(
- "contain.text",
- "dxdt=−0.2ydydt=0.1x+0.3yx(0)=0y(0)=0",
- );
- cy.get(cesc("#\\/ode"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim().replace(/−/g, "-")).equal(
- "dxdt=-0.2ydydt=0.1x+0.3yx(0)=0y(0)=0",
- );
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let ode = stateVariables["/ode"];
- let solutionFx = createFunctionFromDefinition(
- ode.stateValues.numericalSolutionFDefinitions[0],
- );
- let solutionFy = createFunctionFromDefinition(
- ode.stateValues.numericalSolutionFDefinitions[1],
- );
- let solutionFx2 = createFunctionFromDefinition(
- stateVariables["/f1"].stateValues.fDefinitions[0],
- );
- let solutionFy2 = createFunctionFromDefinition(
- stateVariables["/f2"].stateValues.fDefinitions[0],
- );
- let solutionsFromCoreX = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[0]
- .componentName
- ].stateValues.value,
- );
- let solutionsFromCoreY = stateVariables["/_map1"].replacements.map(
- (x) =>
- stateVariables[
- stateVariables[x.componentName].replacements[1]
- .componentName
- ].stateValues.value,
- );
- for (let t = 0; t <= 10; t += 1) {
- expect(solutionFx(t)).eq(0);
- expect(solutionFy(t)).eq(0);
- expect(solutionFx2(t)).eq(solutionFx(t));
- expect(solutionFy2(t)).eq(solutionFy(t));
- expect(solutionsFromCoreX[t]).eq(solutionFx(t));
- expect(solutionsFromCoreY[t]).eq(solutionFy(t));
- }
- });
- });
-
- it("higher dimensional ode", () => {
- cy.log("no variables specified");
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
-
- q
- r
- s
- u
- v
- w
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- let disp = function (vs, rs, is) {
- let s = "";
- for (let i = 0; i < vs.length; i++) {
- s += "d" + vs[i] + "dt=" + rs[i];
- }
- for (let i = 0; i < vs.length; i++) {
- s += vs[i] + "(0)=" + is[i];
- }
- return s;
- };
-
- let vs = ["x1", "x2", "x3", "x4", "x5", "x6"];
- let rs = ["q", "r", "s", "u", "v", "w"];
- let is = ["a", "b", "c", "d", "e", "f"];
-
- cy.get(cesc("#\\/_odesystem1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(disp(vs, rs, is));
- });
-
- cy.log("all variables specified");
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- b
-
- q
- r
- s
- u
- v
- w
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "b"); // to wait for page to load
-
- let vs2 = ["j", "k", "l", "m", "n", "p"];
-
- cy.get(cesc("#\\/_odesystem1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(disp(vs2, rs, is));
- });
-
- cy.log("some variables specified");
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- c
-
- q
- r
- s
- u
- v
- w
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "c"); // to wait for page to load
-
- let vs3 = ["j", "k", "l", "x4", "x5", "x6"];
-
- cy.get(cesc("#\\/_odesystem1"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal(disp(vs3, rs, is));
- });
- });
-
- it("copy righthandside, initial conditions", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
- a
-
- a*x*y+z
- x/y
-
-
- RHS1: $ode.rhs1{name="rhs1a"}
- RHS2: $ode.rhs2{name="rhs2a"}
- RHS1: $ode.rhs{name="rhs1b"}
- Both RHSs: $ode.rhss{name="rhssa"}
- RHS1: $ode.righthandside1{name="rhs1c"}
- RHS2: $ode.righthandside2{name="rhs2b"}
- RHS1: $ode.righthandside{name="rhs1d"}
- Both RHSs: $ode.righthandsides{name="rhssb"}
-
- IC1: $ode.initialcondition1{name="ic1a"}
- IC2: $ode.initialcondition2{name="ic2a"}
- IC1: $ode.initialcondition{name="ic1b"}
- Both ICs: $ode.initialconditions{name="icsa"}
-
- Swap right hand sides and keep initial conditions
-
-
- $ode.rhs2
- $ode.rhs1
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- cy.get(cesc("#\\/_p1") + " .mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("axy+z");
- });
- cy.get(cesc("#\\/_p2"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("xy");
- });
- cy.get(cesc("#\\/_p3"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("axy+z");
- });
- cy.get(cesc("#\\/_p4"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("axy+z");
- });
- cy.get(cesc("#\\/_p4") + " > span:nth-of-type(2)")
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("xy");
- });
- cy.get(cesc("#\\/_p5"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("axy+z");
- });
- cy.get(cesc("#\\/_p6"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("xy");
- });
- cy.get(cesc("#\\/_p7"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("axy+z");
- });
- cy.get(cesc("#\\/_p8"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("axy+z");
- });
- cy.get(cesc("#\\/_p8") + " > span:nth-of-type(2)")
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("xy");
- });
- cy.get(cesc("#\\/_p9"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("c");
- });
- cy.get(cesc("#\\/_p10"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("3");
- });
- cy.get(cesc("#\\/_p11"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("c");
- });
- cy.get(cesc("#\\/_p12"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("c");
- });
- cy.get(cesc("#\\/_p12") + " > span:nth-of-type(2)")
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("3");
- });
-
- cy.get(cesc("#\\/odeswap"))
- .find(".mjx-mrow")
- .eq(0)
- .invoke("text")
- .then((text) => {
- expect(text.trim()).equal("dxdt=xydydt=axy+zx(0)=cy(0)=3");
- });
-
- cy.window().then(async (win) => {
- let stateVariables = await win.returnAllStateVariables1();
- let rhs1tree = ["+", ["*", "a", "x", "y"], "z"];
- let rhs2tree = ["/", "x", "y"];
- expect(
- stateVariables[
- stateVariables["/rhs1a"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(rhs1tree);
- expect(
- stateVariables[
- stateVariables["/rhs1b"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(rhs1tree);
- expect(
- stateVariables[
- stateVariables["/rhs1c"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(rhs1tree);
- expect(
- stateVariables[
- stateVariables["/rhs1d"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(rhs1tree);
- expect(
- stateVariables[
- stateVariables["/rhs2a"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(rhs2tree);
- expect(
- stateVariables[
- stateVariables["/rhs2b"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(rhs2tree);
- expect(
- stateVariables[
- stateVariables["/rhssa"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(rhs1tree);
- expect(
- stateVariables[
- stateVariables["/rhssa"].replacements[1].componentName
- ].stateValues.value,
- ).eqls(rhs2tree);
- expect(
- stateVariables[
- stateVariables["/rhssb"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(rhs1tree);
- expect(
- stateVariables[
- stateVariables["/rhssb"].replacements[1].componentName
- ].stateValues.value,
- ).eqls(rhs2tree);
- expect(
- stateVariables[
- stateVariables["/ic1a"].replacements[0].componentName
- ].stateValues.value,
- ).eqls("c");
- expect(
- stateVariables[
- stateVariables["/ic1b"].replacements[0].componentName
- ].stateValues.value,
- ).eqls("c");
- expect(
- stateVariables[
- stateVariables["/ic2a"].replacements[0].componentName
- ].stateValues.value,
- ).eqls(3);
- expect(
- stateVariables[
- stateVariables["/icsa"].replacements[0].componentName
- ].stateValues.value,
- ).eqls("c");
- expect(
- stateVariables[
- stateVariables["/icsa"].replacements[1].componentName
- ].stateValues.value,
- ).eqls(3);
- });
- });
-
- it("warnings", () => {
- cy.window().then(async (win) => {
- win.postMessage(
- {
- doenetML: `
-a
-
- 5y
-
-
-
- 5y
-
-
-
- 5y
-
-
-
- 5x
- 3x
-
-
- `,
- },
- "*",
- );
- });
-
- cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load
-
- cy.window().then(async (win) => {
- let errorWarnings = await win.returnErrorWarnings1();
-
- expect(errorWarnings.errors.length).eq(0);
- expect(errorWarnings.warnings.length).eq(4);
-
- expect(errorWarnings.warnings[0].message).contain(
- `Invalid value of a variable: sin(x)`,
- );
- expect(errorWarnings.warnings[0].level).eq(1);
- expect(errorWarnings.warnings[0].doenetMLrange.lineBegin).eq(7);
- expect(errorWarnings.warnings[0].doenetMLrange.charBegin).eq(47);
- expect(errorWarnings.warnings[0].doenetMLrange.lineEnd).eq(7);
- expect(errorWarnings.warnings[0].doenetMLrange.charEnd).eq(52);
-
- expect(errorWarnings.warnings[1].message).contain(
- `Variables of must be different than independent variable`,
- );
- expect(errorWarnings.warnings[1].level).eq(1);
- expect(errorWarnings.warnings[1].doenetMLrange.lineBegin).eq(3);
- expect(errorWarnings.warnings[1].doenetMLrange.charBegin).eq(1);
- expect(errorWarnings.warnings[1].doenetMLrange.lineEnd).eq(5);
- expect(errorWarnings.warnings[1].doenetMLrange.charEnd).eq(12);
-
- expect(errorWarnings.warnings[2].message).contain(
- `Invalid value of a variable: sin(y)`,
- );
- expect(errorWarnings.warnings[2].level).eq(1);
- expect(errorWarnings.warnings[2].doenetMLrange.lineBegin).eq(11);
- expect(errorWarnings.warnings[2].doenetMLrange.charBegin).eq(23);
- expect(errorWarnings.warnings[2].doenetMLrange.lineEnd).eq(11);
- expect(errorWarnings.warnings[2].doenetMLrange.charEnd).eq(28);
-
- expect(errorWarnings.warnings[3].message).contain(
- `Can't define ODE RHS functions with duplicate dependent variable names`,
- );
- expect(errorWarnings.warnings[3].level).eq(1);
- expect(errorWarnings.warnings[3].doenetMLrange.lineBegin).eq(15);
- expect(errorWarnings.warnings[3].doenetMLrange.charBegin).eq(1);
- expect(errorWarnings.warnings[3].doenetMLrange.lineEnd).eq(18);
- expect(errorWarnings.warnings[3].doenetMLrange.charEnd).eq(12);
- });
- });
-});