From d13ebb6e5ba4a8e26404155091cdc72ed5a1c4bb Mon Sep 17 00:00:00 2001 From: Duane Nykamp Date: Sat, 19 Oct 2024 17:51:20 -0500 Subject: [PATCH] convert select tests to vitest --- .../doenetml-worker/src/components/AsList.js | 4 +- .../src/test/tagSpecific/select.test.ts | 3278 ++++++++++ .../cypress/e2e/tagSpecific/select.cy.js | 5649 +---------------- 3 files changed, 3281 insertions(+), 5650 deletions(-) create mode 100644 packages/doenetml-worker/src/test/tagSpecific/select.test.ts diff --git a/packages/doenetml-worker/src/components/AsList.js b/packages/doenetml-worker/src/components/AsList.js index 75b0917be..2e965ed60 100644 --- a/packages/doenetml-worker/src/components/AsList.js +++ b/packages/doenetml-worker/src/components/AsList.js @@ -31,7 +31,7 @@ export default class AsList extends InlineComponent { inlineChildren: { dependencyType: "child", childGroups: ["inline"], - variableNames: ["text"], + variableNames: ["text", "hidden"], variablesOptional: true, }, }), @@ -39,7 +39,7 @@ export default class AsList extends InlineComponent { let textpieces = dependencyValues.inlineChildren.map(textFromComponent); - let text = textpieces.join(", "); + let text = textpieces.filter((x) => x).join(", "); return { setValue: { text } }; }, diff --git a/packages/doenetml-worker/src/test/tagSpecific/select.test.ts b/packages/doenetml-worker/src/test/tagSpecific/select.test.ts new file mode 100644 index 000000000..9f091547d --- /dev/null +++ b/packages/doenetml-worker/src/test/tagSpecific/select.test.ts @@ -0,0 +1,3278 @@ +import { describe, expect, it, vi } from "vitest"; +import { createTestCore, returnAllStateVariables } from "../utils/test-core"; +import { + updateBooleanInputValue, + updateMathInputValue, +} from "../utils/actions"; +import me from "math-expressions"; + +const Mock = vi.fn(); +vi.stubGlobal("postMessage", Mock); + +describe("Select tag tests", async () => { + async function test_values_separately({ + doenetML, + componentNames, + selectName, + valid_values, + num_samples, + must_be_distinct = false, + is_math = false, + }: { + doenetML: string; + componentNames: string[]; + selectName?: string; + valid_values: any[][]; + num_samples: number; + must_be_distinct?: boolean; + is_math?: boolean; + }) { + for (let i = 0; i < num_samples; i++) { + let core = await createTestCore({ + doenetML, + requestedVariantIndex: i, + }); + const stateVariables = await returnAllStateVariables(core); + const s = stateVariables[selectName ?? ""]; + for (let [ind, name] of componentNames.entries()) { + let value = name + ? stateVariables[name].stateValues.value + : stateVariables[ + stateVariables[s.replacements![ind].componentName] + .replacements![0].componentName + ].stateValues.value; + expect( + is_math + ? valid_values[ind].some((v) => v.equals(value)) + : valid_values[ind].includes(value), + ).eq(true, `Expected ${value} to be in ${valid_values[ind]}`); + } + + if (must_be_distinct) { + for (let name1 of componentNames) { + let val1 = stateVariables[name1].stateValues.value; + for (let name2 of componentNames) { + if (name2 !== name1) { + let val2 = stateVariables[name2].stateValues.value; + if (is_math) { + expect(val2.equals(val1)).eq(false); + } else { + expect(val2).not.eq(val1); + } + } + } + } + } + } + } + + async function test_combined_values({ + doenetML, + componentNames, + valid_combinations, + num_samples, + is_math = false, + }: { + doenetML: string; + componentNames: string[]; + valid_combinations: any[][]; + num_samples: number; + is_math?: boolean; + }) { + for (let i = 0; i < num_samples; i++) { + let core = await createTestCore({ + doenetML, + requestedVariantIndex: i, + }); + const stateVariables = await returnAllStateVariables(core); + let values = componentNames.map( + (name) => stateVariables[name].stateValues.value, + ); + + expect( + valid_combinations.some((comb) => + comb.every((v, i) => + is_math ? v.equals(values[i]) : v === values[i], + ), + ), + ).eq( + true, + `Expected (${values}) to be in ${valid_combinations.map((comb) => `(${comb})`)}`, + ); + } + } + + it("no parameters, select doesn't do anything", async () => { + let core = await createTestCore({ + doenetML: ` +

+ + + + + + + `; + const valid_values = [ + [ + me.fromText("u"), + me.fromText("v"), + me.fromText("w"), + me.fromText("x"), + me.fromText("y"), + me.fromText("z"), + ], + ]; + const componentNames = ["/res"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 10, + is_math: true, + }); + }); + + it("select multiple maths", async () => { + const doenetML = ` + `; + + const vals = [ + me.fromText("u"), + me.fromText("v"), + me.fromText("w"), + me.fromText("x"), + me.fromText("y"), + me.fromText("z"), + ]; + const valid_values = Array(3).fill(vals); + const componentNames = ["/res1", "/res2", "/res3"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 10, + is_math: true, + must_be_distinct: true, + }); + }); + + it("select multiple maths, initially unresolved", async () => { + const doenetML = ` + + + $n3{name="n2"} + $num1{name="n"} + $n2+$num2 + $n3+$num3 + $num3{name="n3"} + 1`; + const valid_values = [ + [ + me.fromText("u"), + me.fromText("v"), + me.fromText("w"), + me.fromText("x"), + me.fromText("y"), + me.fromText("z"), + ], + [ + me.fromText("u"), + me.fromText("v"), + me.fromText("w"), + me.fromText("x"), + me.fromText("y"), + me.fromText("z"), + ], + [ + me.fromText("u"), + me.fromText("v"), + me.fromText("w"), + me.fromText("x"), + me.fromText("y"), + me.fromText("z"), + ], + ]; + const componentNames = ["/res1", "/res2", "/res3"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 10, + is_math: true, + must_be_distinct: true, + }); + }); + + it("select multiple maths with namespace", async () => { + const doenetML = ` + `; + const vals = [ + me.fromText("u"), + me.fromText("v"), + me.fromText("w"), + me.fromText("x"), + me.fromText("y"), + me.fromText("z"), + ]; + const valid_values = Array(3).fill(vals); + const componentNames = ["/s/res1", "/s/res2", "/s/res3"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 10, + is_math: true, + must_be_distinct: true, + }); + }); + + it("select multiple maths, with replacement", async () => { + const doenetML = ` + `; + const vals = [ + me.fromText("u"), + me.fromText("v"), + me.fromText("w"), + me.fromText("x"), + me.fromText("y"), + me.fromText("z"), + ]; + const valid_values = Array(5).fill(vals); + const componentNames = ["/res1", "/res2", "/res3", "", ""]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + selectName: "/s", + num_samples: 10, + is_math: true, + }); + }); + + it("asList", async () => { + let core = await createTestCore({ + doenetML: ` +

+

1 2 3 4 5 6 7 + +

+ +

+ $sample1{name="noresample1"} + $sample2{name="noresample2"} + $noresample1{name="noreresample1"} + $noresample2{name="noreresample2"} +

+ +

+ +

+ + `, + }); + + let stateVariables = await returnAllStateVariables(core); + let num1 = stateVariables["/n1"].stateValues.value; + let num2 = stateVariables["/n2"].stateValues.value; + expect(Number.isInteger(num1) && num1 >= 1 && num1 <= 7).eq(true); + expect(Number.isInteger(num2) && num2 >= 1 && num2 <= 7).eq(true); + expect( + stateVariables[ + stateVariables[ + stateVariables["/noresample1"].replacements![0] + .componentName + ].replacements![0].componentName + ].stateValues.value, + ).eq(num1); + expect( + stateVariables[ + stateVariables[ + stateVariables["/noresample2"].replacements![0] + .componentName + ].replacements![0].componentName + ].stateValues.value, + ).eq(num2); + expect( + stateVariables[ + stateVariables[ + stateVariables["/noreresample1"].replacements![0] + .componentName + ].replacements![0].componentName + ].stateValues.value, + ).eq(num1); + expect( + stateVariables[ + stateVariables[ + stateVariables["/noreresample2"].replacements![0] + .componentName + ].replacements![0].componentName + ].stateValues.value, + ).eq(num2); + + expect( + stateVariables[ + stateVariables["/noresamplep"].activeChildren[1].componentName + ].stateValues.value, + ).eq(num1); + expect( + stateVariables[ + stateVariables["/noresamplep"].activeChildren[3].componentName + ].stateValues.value, + ).eq(num2); + expect( + stateVariables[ + stateVariables["/noreresamplep"].activeChildren[1].componentName + ].stateValues.value, + ).eq(num1); + expect( + stateVariables[ + stateVariables["/noreresamplep"].activeChildren[3].componentName + ].stateValues.value, + ).eq(num2); + }); + + it("select doesn't change dynamically", async () => { + let core = await createTestCore({ + doenetML: ` + + + + +

+ +

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + let sampleReplacements = stateVariables["/sample1"].replacements!; + expect(sampleReplacements.length).eq(5); + + let sampleMaths = sampleReplacements.map( + (x) => + stateVariables[ + stateVariables[ + stateVariables[x.componentName].replacements![0] + .componentName + ].replacements![0].componentName + ].stateValues.value.tree, + ); + + for (let val of sampleMaths) { + expect(["a", "b", "c"].includes(val)).eq(true); + } + + // Nothing changes when change number to select + await updateMathInputValue({ + latex: "7", + componentName: "/numToSelect", + core, + }); + + stateVariables = await returnAllStateVariables(core); + sampleReplacements = stateVariables["/sample1"].replacements!; + + expect( + sampleReplacements.map( + (x) => + stateVariables[ + stateVariables[ + stateVariables[x.componentName].replacements![0] + .componentName + ].replacements![0].componentName + ].stateValues.value.tree, + ), + ).eqls(sampleMaths); + + // Values change to reflect copy sources + + let newValues = { + a: "q", + b: "r", + c: "s", + }; + await updateMathInputValue({ + latex: newValues.a, + componentName: "/x", + core, + }); + await updateMathInputValue({ + latex: newValues.b, + componentName: "/y", + core, + }); + await updateMathInputValue({ + latex: newValues.c, + componentName: "/z", + core, + }); + + stateVariables = await returnAllStateVariables(core); + sampleReplacements = stateVariables["/sample1"].replacements!; + + let sampleMaths2 = sampleReplacements.map( + (x) => + stateVariables[ + stateVariables[ + stateVariables[x.componentName].replacements![0] + .componentName + ].replacements![0].componentName + ].stateValues.value.tree, + ); + + expect(sampleMaths2).eqls(sampleMaths.map((x) => newValues[x])); + }); + + it("select doesn't resample in dynamic map", async () => { + let core = await createTestCore({ + doenetML: ` + How many numbers do you want? +

+ + + + +

+ +

$map1

+ + $p1{name="p3"} + $p2{name="p4"} + + $p3{name="p5"} + $p4{name="p6"} + `, + }); + + async function check_sampled_numbers(sampledNumbers: number[]) { + const stateVariables = await returnAllStateVariables(core); + + expect( + stateVariables["/p1"].activeChildren.map( + (child) => + stateVariables[child.componentName].stateValues.value, + ), + ).eqls(sampledNumbers); + + expect( + stateVariables["/p2"].activeChildren.map( + (child) => + stateVariables[child.componentName].stateValues.value, + ), + ).eqls(sampledNumbers); + + expect( + stateVariables["/p3"].activeChildren.map( + (child) => + stateVariables[child.componentName].stateValues.value, + ), + ).eqls(sampledNumbers); + + expect( + stateVariables["/p4"].activeChildren.map( + (child) => + stateVariables[child.componentName].stateValues.value, + ), + ).eqls(sampledNumbers); + + expect( + stateVariables["/p5"].activeChildren.map( + (child) => + stateVariables[child.componentName].stateValues.value, + ), + ).eqls(sampledNumbers); + + expect( + stateVariables["/p6"].activeChildren.map( + (child) => + stateVariables[child.componentName].stateValues.value, + ), + ).eqls(sampledNumbers); + } + + let sampledNumbers: number[] = []; + + // initially nothing + await check_sampled_numbers([]); + + // sample one variable + await updateMathInputValue({ latex: "1", componentName: "/mi1", core }); + + let stateVariables = await returnAllStateVariables(core); + sampledNumbers.push(stateVariables["/a/n"].stateValues.value); + await check_sampled_numbers(sampledNumbers); + + // go back to nothing + await updateMathInputValue({ latex: "0", componentName: "/mi1", core }); + await check_sampled_numbers([]); + + // get same number back + await updateMathInputValue({ latex: "1", componentName: "/mi1", core }); + await check_sampled_numbers(sampledNumbers); + + // get two more samples + await updateMathInputValue({ latex: "3", componentName: "/mi1", core }); + + stateVariables = await returnAllStateVariables(core); + let n1 = stateVariables["/a/n"].stateValues.value; + let n2 = stateVariables["/b/n"].stateValues.value; + let n3 = stateVariables["/c/n"].stateValues.value; + expect(n1).eq(sampledNumbers[0]); + sampledNumbers.push(n2); + sampledNumbers.push(n3); + await check_sampled_numbers(sampledNumbers); + + // go back to nothing + await updateMathInputValue({ latex: "0", componentName: "/mi1", core }); + await check_sampled_numbers([]); + + // get first two numbers back + await updateMathInputValue({ latex: "2", componentName: "/mi1", core }); + await check_sampled_numbers(sampledNumbers.slice(0, 2)); + + // get six total samples + await updateMathInputValue({ latex: "6", componentName: "/mi1", core }); + + stateVariables = await returnAllStateVariables(core); + n1 = stateVariables["/a/n"].stateValues.value; + n2 = stateVariables["/b/n"].stateValues.value; + n3 = stateVariables["/c/n"].stateValues.value; + let n4 = stateVariables["/d/n"].stateValues.value; + let n5 = stateVariables["/e/n"].stateValues.value; + let n6 = stateVariables["/f/n"].stateValues.value; + expect(n1).eq(sampledNumbers[0]); + expect(n2).eq(sampledNumbers[1]); + expect(n3).eq(sampledNumbers[2]); + sampledNumbers.push(n4); + sampledNumbers.push(n5); + sampledNumbers.push(n6); + await check_sampled_numbers(sampledNumbers); + + // go back to nothing + await updateMathInputValue({ latex: "0", componentName: "/mi1", core }); + await check_sampled_numbers([]); + + // get all six back + await updateMathInputValue({ latex: "6", componentName: "/mi1", core }); + await check_sampled_numbers(sampledNumbers); + }); + + it("select single group of maths, assign names to grandchildren", async () => { + const doenetML = ` + `; + + const valid_combinations = [ + ["x", "y", "z"].map((x) => me.fromText(x)), + ["u", "v", "w"].map((x) => me.fromText(x)), + ["a", "b", "c"].map((x) => me.fromText(x)), + ["q", "r", "s"].map((x) => me.fromText(x)), + ]; + const componentNames = ["/res1", "/res2", "/res3"]; + + await test_combined_values({ + doenetML, + valid_combinations, + componentNames, + num_samples: 5, + is_math: true, + }); + }); + + it("select single group of maths, assign names with namespace to grandchildren", async () => { + const doenetML = ` + `; + + const valid_combinations = [ + ["x", "y", "z"].map((x) => me.fromText(x)), + ["u", "v", "w"].map((x) => me.fromText(x)), + ["a", "b", "c"].map((x) => me.fromText(x)), + ["q", "r", "s"].map((x) => me.fromText(x)), + ]; + const componentNames = ["/s/res1", "/s/res2", "/s/res3"]; + + await test_combined_values({ + doenetML, + valid_combinations, + componentNames, + num_samples: 5, + is_math: true, + }); + }); + + it("select multiple group of maths, assign names to grandchildren", async () => { + const doenetML = ` + `; + + const valid_combinations = [ + ["x", "y", "z"].map((x) => me.fromText(x)), + ["u", "v", "w"].map((x) => me.fromText(x)), + ["a", "b", "c"].map((x) => me.fromText(x)), + ["q", "r", "s"].map((x) => me.fromText(x)), + ]; + + const allNames = [ + ["/x1", "/y1", "/z1"], + ["/x2", "/y2", "/z2"], + ["/x3", "/y3", "/z3"], + ]; + + for (let componentNames of allNames) { + await test_combined_values({ + doenetML, + valid_combinations, + componentNames, + num_samples: 4, + is_math: true, + }); + } + }); + + it("references to outside components", async () => { + let core = await createTestCore({ + doenetML: ` + x + y + z + + + + a + b + c + +

Selected options repeated

+ $q{name="q2"} + $r{name="r2"} + $s{name="s2"} + $t{name="t2"} + $u{name="u2"} + + `, + }); + + let option = { + "Option 1: ": me.fromText("3xa"), + "Option 2: ": me.fromText("4yb"), + "Option 3: ": me.fromText("5zc"), + }; + + let stateVariables = await returnAllStateVariables(core); + + let q2 = + stateVariables[stateVariables["/q2"].replacements![0].componentName] + .activeChildren; + let q2string = q2[0]; + let q2math = me.fromAst( + stateVariables[q2[1].componentName].stateValues.value, + ); + expect(q2math.equals(option[q2string])).eq(true); + + let r2 = + stateVariables[stateVariables["/r2"].replacements![0].componentName] + .activeChildren; + let r2string = r2[0]; + let r2math = me.fromAst( + stateVariables[r2[1].componentName].stateValues.value, + ); + expect(r2math.equals(option[r2string])).eq(true); + + let s2 = + stateVariables[stateVariables["/s2"].replacements![0].componentName] + .activeChildren; + let s2string = s2[0]; + let s2math = me.fromAst( + stateVariables[s2[1].componentName].stateValues.value, + ); + expect(s2math.equals(option[s2string])).eq(true); + + let t2 = + stateVariables[stateVariables["/t2"].replacements![0].componentName] + .activeChildren; + let t2string = t2[0]; + let t2math = me.fromAst( + stateVariables[t2[1].componentName].stateValues.value, + ); + expect(t2math.equals(option[t2string])).eq(true); + + let u2 = + stateVariables[stateVariables["/u2"].replacements![0].componentName] + .activeChildren; + let u2string = u2[0]; + let u2math = me.fromAst( + stateVariables[u2[1].componentName].stateValues.value, + ); + expect(u2math.equals(option[u2string])).eq(true); + }); + + it("references to outside components, no new namespace", async () => { + let core = await createTestCore({ + doenetML: ` + x + y + z + + + + a + b + c + +

Selected options repeated

+ $q{name="q2"} + $r{name="r2"} + $s{name="s2"} + $t{name="t2"} + $u{name="u2"} + + `, + }); + + let option = { + "Option 1: ": me.fromText("3xa"), + "Option 2: ": me.fromText("4yb"), + "Option 3: ": me.fromText("5zc"), + }; + + let stateVariables = await returnAllStateVariables(core); + + let q2 = + stateVariables[stateVariables["/q2"].replacements![0].componentName] + .activeChildren; + let q2string = q2[0]; + let q2math = me.fromAst( + stateVariables[q2[1].componentName].stateValues.value, + ); + expect(q2math.equals(option[q2string])).eq(true); + + let r2 = + stateVariables[stateVariables["/r2"].replacements![0].componentName] + .activeChildren; + let r2string = r2[0]; + let r2math = me.fromAst( + stateVariables[r2[1].componentName].stateValues.value, + ); + expect(r2math.equals(option[r2string])).eq(true); + + let s2 = + stateVariables[stateVariables["/s2"].replacements![0].componentName] + .activeChildren; + let s2string = s2[0]; + let s2math = me.fromAst( + stateVariables[s2[1].componentName].stateValues.value, + ); + expect(s2math.equals(option[s2string])).eq(true); + + let t2 = + stateVariables[stateVariables["/t2"].replacements![0].componentName] + .activeChildren; + let t2string = t2[0]; + let t2math = me.fromAst( + stateVariables[t2[1].componentName].stateValues.value, + ); + expect(t2math.equals(option[t2string])).eq(true); + + let u2 = + stateVariables[stateVariables["/u2"].replacements![0].componentName] + .activeChildren; + let u2string = u2[0]; + let u2math = me.fromAst( + stateVariables[u2[1].componentName].stateValues.value, + ); + expect(u2math.equals(option[u2string])).eq(true); + }); + + it("internal references", async () => { + let core = await createTestCore({ + doenetML: ` + + +

Selected options repeated

+ $q{name="q2"} + $r{name="r2"} + $s{name="s2"} + $t{name="t2"} + $u{name="u2"} + +

Copy x from within selection options

+

$(q/x{name="qx"})

+

$(r/x{name="rx"})

+

$(s/x{name="sx"})

+

$(t/x{name="tx"})

+

$(u/x{name="ux"})

+ +

Copy select itself

+
$s1
+ + `, + }); + + let option = { + "Option 1: ": me.fromText("3x+a+x^2a^3"), + "Option 2: ": me.fromText("4y+b+y^2b^3"), + "Option 3: ": me.fromText("5z+c+z^2c^3"), + }; + + let xoption = { + "Option 1: ": "x", + "Option 2: ": "y", + "Option 3: ": "z", + }; + + let stateVariables = await returnAllStateVariables(core); + + let q2 = + stateVariables[stateVariables["/q2"].replacements![0].componentName] + .activeChildren; + let q2string = q2[0]; + let q2math = stateVariables[q2[1].componentName].stateValues.value; + expect(q2math.equals(option[q2string])).eq(true); + let qx = stateVariables["/qx"].stateValues.value.tree; + expect(qx).eq(xoption[q2string]); + let repeatqmath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[0].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeatqmath.equals(option[q2string])).eq(true); + + let r2 = + stateVariables[stateVariables["/r2"].replacements![0].componentName] + .activeChildren; + let r2string = r2[0]; + let r2math = stateVariables[r2[1].componentName].stateValues.value; + expect(r2math.equals(option[r2string])).eq(true); + let rx = stateVariables["/rx"].stateValues.value.tree; + expect(rx).eq(xoption[r2string]); + let repeatrmath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[1].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeatrmath.equals(option[r2string])).eq(true); + + let s2 = + stateVariables[stateVariables["/s2"].replacements![0].componentName] + .activeChildren; + let s2string = s2[0]; + let s2math = stateVariables[s2[1].componentName].stateValues.value; + expect(s2math.equals(option[s2string])).eq(true); + let sx = stateVariables["/sx"].stateValues.value.tree; + expect(sx).eq(xoption[s2string]); + let repeatsmath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[2].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeatsmath.equals(option[s2string])).eq(true); + + let t2 = + stateVariables[stateVariables["/t2"].replacements![0].componentName] + .activeChildren; + let t2string = t2[0]; + let t2math = stateVariables[t2[1].componentName].stateValues.value; + expect(t2math.equals(option[t2string])).eq(true); + let tx = stateVariables["/tx"].stateValues.value.tree; + expect(tx).eq(xoption[t2string]); + let repeattmath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[3].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeattmath.equals(option[t2string])).eq(true); + + let u2 = + stateVariables[stateVariables["/u2"].replacements![0].componentName] + .activeChildren; + let u2string = u2[0]; + let u2math = stateVariables[u2[1].componentName].stateValues.value; + expect(u2math.equals(option[u2string])).eq(true); + let ux = stateVariables["/ux"].stateValues.value.tree; + expect(ux).eq(xoption[u2string]); + let repeatumath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[4].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeatumath.equals(option[u2string])).eq(true); + }); + + it("internal references with no new namespace", async () => { + let core = await createTestCore({ + doenetML: ` + + +

Selected options repeated

+ $q{name="q2"} + $r{name="r2"} + $s{name="s2"} + $t{name="t2"} + $u{name="u2"} + +

Copy select itself

+
$s1
+ + `, + }); + + let option = { + "Option 1: ": me.fromText("3x+a+x^2a^3"), + "Option 2: ": me.fromText("4y+b+y^2b^3"), + "Option 3: ": me.fromText("5z+c+z^2c^3"), + }; + + let xoption = { + "Option 1: ": "x", + "Option 2: ": "y", + "Option 3: ": "z", + }; + + let stateVariables = await returnAllStateVariables(core); + + let q2 = + stateVariables[stateVariables["/q2"].replacements![0].componentName] + .activeChildren; + let q2string = q2[0]; + let q2math = stateVariables[q2[1].componentName].stateValues.value; + expect(q2math.equals(option[q2string])).eq(true); + let repeatqmath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[0].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeatqmath.equals(option[q2string])).eq(true); + + let r2 = + stateVariables[stateVariables["/r2"].replacements![0].componentName] + .activeChildren; + let r2string = r2[0]; + let r2math = stateVariables[r2[1].componentName].stateValues.value; + expect(r2math.equals(option[r2string])).eq(true); + let repeatrmath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[1].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeatrmath.equals(option[r2string])).eq(true); + + let s2 = + stateVariables[stateVariables["/s2"].replacements![0].componentName] + .activeChildren; + let s2string = s2[0]; + let s2math = stateVariables[s2[1].componentName].stateValues.value; + expect(s2math.equals(option[s2string])).eq(true); + let repeatsmath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[2].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeatsmath.equals(option[s2string])).eq(true); + + let t2 = + stateVariables[stateVariables["/t2"].replacements![0].componentName] + .activeChildren; + let t2string = t2[0]; + let t2math = stateVariables[t2[1].componentName].stateValues.value; + expect(t2math.equals(option[t2string])).eq(true); + let repeattmath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[3].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeattmath.equals(option[t2string])).eq(true); + + let u2 = + stateVariables[stateVariables["/u2"].replacements![0].componentName] + .activeChildren; + let u2string = u2[0]; + let u2math = stateVariables[u2[1].componentName].stateValues.value; + expect(u2math.equals(option[u2string])).eq(true); + let repeatumath = + stateVariables[ + stateVariables[ + stateVariables["/repeat"].activeChildren[4].componentName + ].activeChildren[1].componentName + ].stateValues.value; + expect(repeatumath.equals(option[u2string])).eq(true); + }); + + it("variant names specified, select single", async () => { + let core = await createTestCore({ + doenetML: ` + + +

Selected variable: + +

+ +

Selected variable repeated: $x{name="x2"}

+

Selected variable repeated again: $s1{name="x3"}

+ `, + requestedVariantIndex: 2, + }); + + let stateVariables = await returnAllStateVariables(core); + + // let variantName = stateVariables['/x'].sharedParameters.variantName; + // let expectedx = variantName.substring(0, 1); + let expectedx = "b"; + + let x = stateVariables["/x"].stateValues.value.tree; + + expect(x).eq(expectedx); + + let xorig = + stateVariables[ + stateVariables[ + stateVariables["/s1"].replacements![0].componentName + ].replacements![0].componentName + ].stateValues.value.tree; + expect(xorig).eq(expectedx); + + let x2 = stateVariables["/x2"].stateValues.value.tree; + expect(x2).eq(expectedx); + + let x3 = + stateVariables[ + stateVariables[ + stateVariables["/x3"].replacements![0].componentName + ].replacements![0].componentName + ].stateValues.value.tree; + expect(x3).eq(expectedx); + }); + + it("variant names specified, select multiple", async () => { + let core = await createTestCore({ + doenetML: ` + + +

Selected variables: + +

+ +

Selected first variable: $x{name="x2"}

+

Selected second variable: $y{name="y2"}

+

Selected third variable: $z{name="z2"}

+

Selected variables repeated: $s1{name="s2"}

+ + `, + requestedVariantIndex: 3, + }); + + let stateVariables = await returnAllStateVariables(core); + + let variantMap = { + avocado: ["d", "a", "a"], + broccoli: ["e", "a", "b"], + carrot: ["d", "c", "b"], + dill: ["d", "e", "b"], + eggplant: ["c", "c", "e"], + }; + + // let variantName = stateVariables['/x'].sharedParameters.variantName; + let variantName = "carrot"; + let variantVars = variantMap[variantName]; + + let x = stateVariables["/x"].stateValues.value.tree; + + expect(variantVars.includes(x)).eq(true); + variantVars.splice(variantVars.indexOf(x), 1); + + let y = stateVariables["/y"].stateValues.value.tree; + expect(variantVars.includes(y)).eq(true); + variantVars.splice(variantVars.indexOf(y), 1); + + let z = stateVariables["/z"].stateValues.value.tree; + expect(z).eq(variantVars[0]); + + let xorig = + stateVariables[ + stateVariables[ + stateVariables["/s1"].replacements![0].componentName + ].replacements![0].componentName + ].stateValues.value.tree; + expect(xorig).eq(x); + let yorig = + stateVariables[ + stateVariables[ + stateVariables["/s1"].replacements![1].componentName + ].replacements![0].componentName + ].stateValues.value.tree; + expect(yorig).eq(y); + let zorig = + stateVariables[ + stateVariables[ + stateVariables["/s1"].replacements![2].componentName + ].replacements![0].componentName + ].stateValues.value.tree; + expect(zorig).eq(z); + + let x2 = stateVariables["/x2"].stateValues.value.tree; + expect(x2).eq(x); + let y2 = stateVariables["/y2"].stateValues.value.tree; + expect(y2).eq(y); + let z2 = stateVariables["/z2"].stateValues.value.tree; + expect(z2).eq(z); + + let x3 = + stateVariables[ + stateVariables[ + stateVariables["/s2"].replacements![0].componentName + ].replacements![0].componentName + ].stateValues.value.tree; + expect(x3).eq(x); + let y3 = + stateVariables[ + stateVariables[ + stateVariables["/s2"].replacements![1].componentName + ].replacements![0].componentName + ].stateValues.value.tree; + expect(y3).eq(y); + let z3 = + stateVariables[ + stateVariables[ + stateVariables["/s2"].replacements![2].componentName + ].replacements![0].componentName + ].stateValues.value.tree; + expect(z3).eq(z); + }); + + it("select math as sugared string", async () => { + const doenetML = ` + `; + + const vals = ["x^2", "x/y", "u", "a", "b-c", "s+t", "mn", "-1"].map( + (x) => me.fromText(x), + ); + + const valid_values = Array(5).fill(vals); + const componentNames = ["/m1", "/m2", "/m3", "/m4", "/m5"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 2, + is_math: true, + must_be_distinct: true, + }); + }); + + it("select math as sugared string, no type specified", async () => { + const doenetML = ` + `; + + const vals = ["x^2", "x/y", "u", "a", "b-c", "s+t", "mn", "-1"].map( + (x) => me.fromText(x), + ); + + const valid_values = Array(5).fill(vals); + const componentNames = ["/m1", "/m2", "/m3", "/m4", "/m5"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 2, + is_math: true, + must_be_distinct: true, + }); + }); + + it("select math as sugared strings and macros", async () => { + const doenetML = ` + + x + y + 7 + -3 + + `; + + const vals = ["7x^2", "(-3)x/y", "u-(-3)", "7", "x-c", "y"].map((x) => + me.fromText(x), + ); + + const valid_values = Array(6).fill(vals); + const componentNames = ["/m1", "/m2", "/m3", "/m4", "/m5", "/m6"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 2, + is_math: true, + must_be_distinct: true, + }); + }); + + it("select text as sugared string", async () => { + const doenetML = ` + `; + + const vals = [ + "Lorem", + "ipsum", + "dolor", + "sit", + "amet", + "consectetur", + "adipiscing", + "elit", + ]; + + const valid_values = Array(5).fill(vals); + const componentNames = ["/w1", "/w2", "/w3", "/w4", "/w5"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 2, + must_be_distinct: true, + }); + }); + + it("select text as sugared strings and macros", async () => { + const doenetML = ` + + amet + consectetur + dolor + + `; + + const vals = [ + "Lorem", + "ipsum dolor", + "sit", + "amet", + "consectetur adipiscing", + ]; + + const valid_values = Array(5).fill(vals); + const componentNames = ["/w1", "/w2", "/w3", "/w4", "/w5"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 2, + must_be_distinct: true, + }); + }); + + it("select number as sugared string", async () => { + const doenetML = ` + `; + + const vals = [2, 3, 5, 7, 11, 13, 17, 19]; + const valid_values = Array(10).fill(vals); + + const componentNames = [ + "/n1", + "/n2", + "/n3", + "/n4", + "/n5", + "/n6", + "/n7", + "/n8", + "/n9", + "/n10", + ]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 2, + }); + }); + + it("select number as sugared strings and macros", async () => { + const doenetML = ` + + 5 + -7 + 6+2 + + `; + + const vals = [2, -2, -5, 5, -8, 8]; + const valid_values = Array(6).fill(vals); + + const componentNames = ["/n1", "/n2", "/n3", "/n4", "/n5", "/n6"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 2, + must_be_distinct: true, + }); + }); + + it("select boolean as sugared string", async () => { + const doenetML = ` + `; + + const vals = [true, false]; + const valid_values = Array(10).fill(vals); + + const componentNames = [ + "/b1", + "/b2", + "/b3", + "/b4", + "/b5", + "/b6", + "/b7", + "/b8", + "/b9", + "/b10", + ]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 1, + }); + }); + + it("select boolean as sugared strings and macros", async () => { + const doenetML = ` + + true + false + + `; + + const vals = [true, false]; + const valid_values = Array(10).fill(vals); + + const componentNames = [ + "/b1", + "/b2", + "/b3", + "/b4", + "/b5", + "/b6", + "/b7", + "/b8", + "/b9", + "/b10", + ]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 1, + }); + }); + + it("select invalid type with sugared string, becomes math with warning", async () => { + const doenetML = ` + `; + + const vals = ["x^2", "x/y", "u", "a", "b-c", "s+t", "mn", "-1"].map( + (x) => me.fromText(x), + ); + + const valid_values = Array(5).fill(vals); + const componentNames = ["/m1", "/m2", "/m3", "/m4", "/m5"]; + + await test_values_separately({ + doenetML, + valid_values, + componentNames, + num_samples: 2, + is_math: true, + must_be_distinct: true, + }); + + let core = await createTestCore({ doenetML }); + + let errorWarnings = core.errorWarnings; + + expect(errorWarnings.errors.length).eq(0); + expect(errorWarnings.warnings.length).eq(1); + + expect(errorWarnings.warnings[0].message).contain( + "Invalid type for select: nothing", + ); + expect(errorWarnings.warnings[0].level).eq(1); + expect(errorWarnings.warnings[0].doenetMLrange.lineBegin).eq(2); + expect(errorWarnings.warnings[0].doenetMLrange.charBegin).eq(5); + expect(errorWarnings.warnings[0].doenetMLrange.lineEnd).eq(4); + expect(errorWarnings.warnings[0].doenetMLrange.charEnd).eq(13); + }); + + it("select weighted", async () => { + // TODO: this test seems to fail with num Y < 17 once in awhile + // even though it should fail less than 0.1% of the time + // Is there a flaw? + + let core = await createTestCore({ + doenetML: ` + + + + + `, + }); + + let numX = 0, + numY = 0, + numZ = 0; + + let stateVariables = await returnAllStateVariables(core); + for (let ind = 0; ind < 200; ind++) { + let theText = + stateVariables[ + stateVariables[ + stateVariables[ + stateVariables[ + stateVariables["/_map1"].replacements![ind] + .componentName + ].replacements![1].componentName + ].replacements![0].componentName + ].replacements![0].componentName + ]; + let x = theText.stateValues.value; + if (x === "z") { + numZ++; + } else if (x === "y") { + numY++; + } else { + numX++; + } + } + + expect(numX).greaterThan(0); + expect(numX).lessThan(15); + expect(numY).greaterThan(17); + expect(numY).lessThan(50); + expect(numZ).greaterThan(140); + }); + + it("select weighted with replacement", async () => { + let core = await createTestCore({ + doenetML: ` + + `, + requestedVariantIndex: 0, + }); + + let stateVariables = await returnAllStateVariables(core); + let numX = 0, + numY = 0, + numZ = 0; + let selectReplacements = stateVariables["/_select1"].replacements!; + for (let ind = 0; ind < 200; ind++) { + let x = + stateVariables[ + stateVariables[selectReplacements[ind].componentName] + .replacements![0].componentName + ].stateValues.value; + if (x === "x") { + numX++; + } else if (x === "y") { + numY++; + } else { + numZ++; + } + } + expect(numX).greaterThan(0); + expect(numX).lessThan(15); + expect(numY).greaterThan(20); + expect(numY).lessThan(50); + expect(numZ).greaterThan(150); + }); + + it("select weighted without replacement", async () => { + let core = await createTestCore({ + doenetML: ` + + + + + `, + }); + + let numX = 0, + numY = 0, + numZ = 0, + numUVW = 0; + + let stateVariables = await returnAllStateVariables(core); + + for (let ind = 0; ind < 200; ind++) { + let theSelect = + stateVariables[ + stateVariables[ + stateVariables["/_map1"].replacements![ind] + .componentName + ].replacements![1].componentName + ]; + let theText1 = + stateVariables[ + stateVariables[theSelect.replacements![0].componentName] + .replacements![0].componentName + ]; + let x = theText1.stateValues.value; + + if (x === "z") { + numZ++; + } else if (x === "y") { + numY++; + } else if (x === "x") { + numX++; + } else { + numUVW++; + } + let theText2 = + stateVariables[ + stateVariables[theSelect.replacements![1].componentName] + .replacements![0].componentName + ]; + let y = theText2.stateValues.value; + if (y === "z") { + numZ++; + } else if (y === "y") { + numY++; + } else if (y === "x") { + numX++; + } else { + numUVW++; + } + } + + expect(numUVW).greaterThan(0); + expect(numUVW).lessThan(20); + expect(numX).greaterThan(150); + expect(numY).greaterThan(10); + expect(numY).lessThan(50); + expect(numZ).greaterThan(170); + }); + + it("references to internal assignnames", async () => { + let core = await createTestCore({ + doenetML: ` + a e i o u$q{name="q2"}$r{name="r2"}

+ + + + + +

Selected options repeated

+ $q{name="q2"} + $r{name="r2"} + $s{name="s2"} + $t{name="t2"} + $u{name="u2"} + $v{name="v2"} + $w{name="w2"} + +

Copy q and r and their copies from within selected options

+

$(q/q{name="qq"})$(q/r{name="qr"})$(q/q2{name="qq2"})$(q/r2{name="qr2"})

+

$(r/q{name="rq"})$(r/r{name="rr"})$(r/q2{name="rq2"})$(r/r2{name="rr2"})

+

$(s/q{name="sq"})$(s/r{name="sr"})$(s/q2{name="sq2"})$(s/r2{name="sr2"})

+

$(t/q{name="tq"})$(t/r{name="tr"})$(t/q2{name="tq2"})$(t/r2{name="tr2"})

+

$(u/q{name="uq"})$(u/r{name="ur"})$(u/q2{name="uq2"})$(u/r2{name="ur2"})

+

$(v/q{name="vq"})$(v/r{name="vr"})$(v/q2{name="vq2"})$(v/r2{name="vr2"})

+

$(w/q{name="wq"})$(w/r{name="wr"})$(w/q2{name="wq2"})$(w/r2{name="wr2"})

+ + `, + }); + + let stateVariables = await returnAllStateVariables(core); + let qs = stateVariables["/q"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let rs = stateVariables["/r"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let ss = stateVariables["/s"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let ts = stateVariables["/t"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let us = stateVariables["/u"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let vs = stateVariables["/v"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let ws = stateVariables["/w"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + + let q2s = stateVariables["/q2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let r2s = stateVariables["/r2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let s2s = stateVariables["/s2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let t2s = stateVariables["/t2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let u2s = stateVariables["/u2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let v2s = stateVariables["/v2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let w2s = stateVariables["/w2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + + const getTree = (x) => x.tree ?? x; + + expect(q2s.map(getTree)).eqls(qs.map(getTree)); + expect(r2s.map(getTree)).eqls(rs.map(getTree)); + expect(s2s.map(getTree)).eqls(ss.map(getTree)); + expect(t2s.map(getTree)).eqls(ts.map(getTree)); + expect(u2s.map(getTree)).eqls(us.map(getTree)); + expect(v2s.map(getTree)).eqls(vs.map(getTree)); + expect(w2s.map(getTree)).eqls(ws.map(getTree)); + + let q3s = [ + stateVariables["/qq"].stateValues.value, + stateVariables["/qr"].stateValues.value, + stateVariables["/qq2"].stateValues.value, + stateVariables["/qr2"].stateValues.value, + ]; + let r3s = [ + stateVariables["/rq"].stateValues.value, + stateVariables["/rr"].stateValues.value, + stateVariables["/rq2"].stateValues.value, + stateVariables["/rr2"].stateValues.value, + ]; + let s3s = [ + stateVariables["/sq"].stateValues.value, + stateVariables["/sr"].stateValues.value, + stateVariables["/sq2"].stateValues.value, + stateVariables["/sr2"].stateValues.value, + ]; + let t3s = [ + stateVariables["/tq"].stateValues.value, + stateVariables["/tr"].stateValues.value, + stateVariables["/tq2"].stateValues.value, + stateVariables["/tr2"].stateValues.value, + ]; + let u3s = [ + stateVariables["/uq"].stateValues.value, + stateVariables["/ur"].stateValues.value, + stateVariables["/uq2"].stateValues.value, + stateVariables["/ur2"].stateValues.value, + ]; + let v3s = [ + stateVariables["/vq"].stateValues.value, + stateVariables["/vr"].stateValues.value, + stateVariables["/vq2"].stateValues.value, + stateVariables["/vr2"].stateValues.value, + ]; + let w3s = [ + stateVariables["/wq"].stateValues.value, + stateVariables["/wr"].stateValues.value, + stateVariables["/wq2"].stateValues.value, + stateVariables["/wr2"].stateValues.value, + ]; + + expect(q3s.map(getTree)).eqls(qs.map(getTree)); + expect(r3s.map(getTree)).eqls(rs.map(getTree)); + expect(s3s.map(getTree)).eqls(ss.map(getTree)); + expect(t3s.map(getTree)).eqls(ts.map(getTree)); + expect(u3s.map(getTree)).eqls(us.map(getTree)); + expect(v3s.map(getTree)).eqls(vs.map(getTree)); + expect(w3s.map(getTree)).eqls(ws.map(getTree)); + }); + + it("references to internal assignnames, newnamespaces", async () => { + let core = await createTestCore({ + doenetML: ` + a e i o u$(s/q{name="q2"})$(s/r{name="r2"})

+ + + + +

Selected options repeated

+ $q{name="q2"} + $r{name="r2"} + $s{name="s2"} + $t{name="t2"} + $u{name="u2"} + $v{name="v2"} + $w{name="w2"} + +

Selected options repeated, no p

+

$(q/s{name="q3"})

+

$(r/s{name="r3"})

+

$(s/s{name="s3"})

+

$(t/s{name="t3"})

+

$(u/s{name="u3"})

+

$(v/s{name="v3"})

+

$(w/s{name="w3"})

+ +

Copy q and r from within selected options

+

$(q/s/q{name="qq"})$(q/s/r{name="qr"})$(q/q2{name="qq2"})$(q/r2{name="qr2"})

+

$(r/s/q{name="rq"})$(r/s/r{name="rr"})$(r/q2{name="rq2"})$(r/r2{name="rr2"})

+

$(s/s/q{name="sq"})$(s/s/r{name="sr"})$(s/q2{name="sq2"})$(s/r2{name="sr2"})

+

$(t/s/q{name="tq"})$(t/s/r{name="tr"})$(t/q2{name="tq2"})$(t/r2{name="tr2"})

+

$(u/s/q{name="uq"})$(u/s/r{name="ur"})$(u/q2{name="uq2"})$(u/r2{name="ur2"})

+

$(v/s/q{name="vq"})$(v/s/r{name="vr"})$(v/q2{name="vq2"})$(v/r2{name="vr2"})

+

$(w/s/q{name="wq"})$(w/s/r{name="wr"})$(w/q2{name="wq2"})$(w/r2{name="wr2"})

+ + `, + }); + + let stateVariables = await returnAllStateVariables(core); + let qs = stateVariables["/q"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let rs = stateVariables["/r"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let ss = stateVariables["/s"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let ts = stateVariables["/t"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let us = stateVariables["/u"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let vs = stateVariables["/v"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let ws = stateVariables["/w"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + + let q2s = stateVariables["/q2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let r2s = stateVariables["/r2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let s2s = stateVariables["/s2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let t2s = stateVariables["/t2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let u2s = stateVariables["/u2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let v2s = stateVariables["/v2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + let w2s = stateVariables["/w2"].activeChildren.map( + (x) => stateVariables[x.componentName].stateValues.value, + ); + + const getTree = (x) => x.tree ?? x; + + expect(q2s.map(getTree)).eqls(qs.map(getTree)); + expect(r2s.map(getTree)).eqls(rs.map(getTree)); + expect(s2s.map(getTree)).eqls(ss.map(getTree)); + expect(t2s.map(getTree)).eqls(ts.map(getTree)); + expect(u2s.map(getTree)).eqls(us.map(getTree)); + expect(v2s.map(getTree)).eqls(vs.map(getTree)); + expect(w2s.map(getTree)).eqls(ws.map(getTree)); + + let q3s = stateVariables["/q3"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let r3s = stateVariables["/r3"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let s3s = stateVariables["/s3"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let t3s = stateVariables["/t3"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let u3s = stateVariables["/u3"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let v3s = stateVariables["/v3"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let w3s = stateVariables["/w3"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + + expect(q3s.map(getTree)).eqls(qs.slice(0, 2).map(getTree)); + expect(r3s.map(getTree)).eqls(rs.slice(0, 2).map(getTree)); + expect(s3s.map(getTree)).eqls(ss.slice(0, 2).map(getTree)); + expect(t3s.map(getTree)).eqls(ts.slice(0, 2).map(getTree)); + expect(u3s.map(getTree)).eqls(us.slice(0, 2).map(getTree)); + expect(v3s.map(getTree)).eqls(vs.slice(0, 2).map(getTree)); + expect(w3s.map(getTree)).eqls(ws.slice(0, 2).map(getTree)); + + let q4s = [ + stateVariables["/qq"].stateValues.value, + stateVariables["/qr"].stateValues.value, + stateVariables["/qq2"].stateValues.value, + stateVariables["/qr2"].stateValues.value, + ]; + let r4s = [ + stateVariables["/rq"].stateValues.value, + stateVariables["/rr"].stateValues.value, + stateVariables["/rq2"].stateValues.value, + stateVariables["/rr2"].stateValues.value, + ]; + let s4s = [ + stateVariables["/sq"].stateValues.value, + stateVariables["/sr"].stateValues.value, + stateVariables["/sq2"].stateValues.value, + stateVariables["/sr2"].stateValues.value, + ]; + let t4s = [ + stateVariables["/tq"].stateValues.value, + stateVariables["/tr"].stateValues.value, + stateVariables["/tq2"].stateValues.value, + stateVariables["/tr2"].stateValues.value, + ]; + let u4s = [ + stateVariables["/uq"].stateValues.value, + stateVariables["/ur"].stateValues.value, + stateVariables["/uq2"].stateValues.value, + stateVariables["/ur2"].stateValues.value, + ]; + let v4s = [ + stateVariables["/vq"].stateValues.value, + stateVariables["/vr"].stateValues.value, + stateVariables["/vq2"].stateValues.value, + stateVariables["/vr2"].stateValues.value, + ]; + let w4s = [ + stateVariables["/wq"].stateValues.value, + stateVariables["/wr"].stateValues.value, + stateVariables["/wq2"].stateValues.value, + stateVariables["/wr2"].stateValues.value, + ]; + + expect(q4s.map(getTree)).eqls(qs.map(getTree)); + expect(r4s.map(getTree)).eqls(rs.map(getTree)); + expect(s4s.map(getTree)).eqls(ss.map(getTree)); + expect(t4s.map(getTree)).eqls(ts.map(getTree)); + expect(u4s.map(getTree)).eqls(us.map(getTree)); + expect(v4s.map(getTree)).eqls(vs.map(getTree)); + expect(w4s.map(getTree)).eqls(ws.map(getTree)); + }); + + it("references to select of selects", async () => { + let core = await createTestCore({ + doenetML: ` + a e i o u + + + +

Selected options repeated

+

$q{name="q2"}

+

$r{name="r2"}

+

$s{name="s2"}

+

$t{name="t2"}

+

$u{name="u2"}

+ +

Copy x/q and x/r

+

$(q/q{name="qq"})$(q/r{name="qr"})

+

$(r/q{name="rq"})$(r/r{name="rr"})

+

$(s/q{name="sq"})$(s/r{name="sr"})

+

$(t/q{name="tq"})$(t/r{name="tr"})

+

$(u/q{name="uq"})$(u/r{name="ur"})

+ + `, + }); + + let stateVariables = await returnAllStateVariables(core); + let qs = stateVariables["/q"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let rs = stateVariables["/r"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let ss = stateVariables["/s"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let ts = stateVariables["/t"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let us = stateVariables["/u"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + + let q2s = stateVariables["/q2"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let r2s = stateVariables["/r2"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let s2s = stateVariables["/s2"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let t2s = stateVariables["/t2"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + let u2s = stateVariables["/u2"] + .replacements!.map((x) => stateVariables[x.componentName]) + .map((x) => + x.replacements + ? stateVariables[x.replacements[0].componentName] + .stateValues.value + : x.stateValues.value, + ); + + const getTree = (x) => x.tree ?? x; + + expect(q2s.map(getTree)).eqls(qs.map(getTree)); + expect(r2s.map(getTree)).eqls(rs.map(getTree)); + expect(s2s.map(getTree)).eqls(ss.map(getTree)); + expect(t2s.map(getTree)).eqls(ts.map(getTree)); + expect(u2s.map(getTree)).eqls(us.map(getTree)); + + let q3s = [ + stateVariables["/qq"].stateValues.value, + stateVariables["/qr"].stateValues.value, + ]; + let r3s = [ + stateVariables["/rq"].stateValues.value, + stateVariables["/rr"].stateValues.value, + ]; + let s3s = [ + stateVariables["/sq"].stateValues.value, + stateVariables["/sr"].stateValues.value, + ]; + let t3s = [ + stateVariables["/tq"].stateValues.value, + stateVariables["/tr"].stateValues.value, + ]; + let u3s = [ + stateVariables["/uq"].stateValues.value, + stateVariables["/ur"].stateValues.value, + ]; + + expect(q3s.map(getTree)).eqls(qs.map(getTree)); + expect(r3s.map(getTree)).eqls(rs.map(getTree)); + expect(s3s.map(getTree)).eqls(ss.map(getTree)); + expect(t3s.map(getTree)).eqls(ts.map(getTree)); + expect(u3s.map(getTree)).eqls(us.map(getTree)); + }); + + it("references to select of selects of selects", async () => { + let core = await createTestCore({ + doenetML: ` + + + + + + + + + + + +

Selected options repeated

+

$q{name="q2"}

+

$r{name="r2"}

+

$s{name="s2"}

+ +

Copy x/q, x/r, x/s

+

$(q/q{name="qq"})$(q/r{name="qr"})$(q/s{name="qs"})

+

$(r/q{name="rq"})$(r/r{name="rr"})$(r/s{name="rs"})

+

$(s/q{name="sq"})$(s/r{name="sr"})$(s/s{name="ss"})

+ +

Copy x/x/q, x/x/r

+

$(q/q/q{name="qqq"})$(q/q/r{name="qqr"})$(q/r/q{name="qrq"})$(q/r/r{name="qrr"})$(q/s/q{name="qsq"})$(q/s/r{name="qsr"})

+

$(r/q/q{name="rqq"})$(r/q/r{name="rqr"})$(r/r/q{name="rrq"})$(r/r/r{name="rrr"})$(r/s/q{name="rsq"})$(r/s/r{name="rsr"})

+

$(s/q/q{name="sqq"})$(s/q/r{name="sqr"})$(s/r/q{name="srq"})$(s/r/r{name="srr"})$(s/s/q{name="ssq"})$(s/s/r{name="ssr"})

+ + `, + }); + + let stateVariables = await returnAllStateVariables(core); + let qs = [ + "/q/q/q", + "/q/q/r", + "/q/r/q", + "/q/r/r", + "/q/s/q", + "/q/s/r", + ].map((x) => + stateVariables[x].replacements + ? stateVariables[ + stateVariables[x].replacements[0].componentName + ].stateValues.value + : stateVariables[x].stateValues.value, + ); + let rs = [ + "/r/q/q", + "/r/q/r", + "/r/r/q", + "/r/r/r", + "/r/s/q", + "/r/s/r", + ].map((x) => + stateVariables[x].replacements + ? stateVariables[ + stateVariables[x].replacements[0].componentName + ].stateValues.value + : stateVariables[x].stateValues.value, + ); + let ss = [ + "/s/q/q", + "/s/q/r", + "/s/r/q", + "/s/r/r", + "/s/s/q", + "/s/s/r", + ].map((x) => + stateVariables[x].replacements + ? stateVariables[ + stateVariables[x].replacements[0].componentName + ].stateValues.value + : stateVariables[x].stateValues.value, + ); + + expect(stateVariables["/pq2"].stateValues.text.replace(/, /g, "")).eq( + qs.join(""), + ); + expect(stateVariables["/pr2"].stateValues.text.replace(/, /g, "")).eq( + rs.join(""), + ); + expect(stateVariables["/ps2"].stateValues.text.replace(/, /g, "")).eq( + ss.join(""), + ); + + expect(stateVariables["/pq3"].stateValues.text.replace(/, /g, "")).eq( + qs.join(""), + ); + expect(stateVariables["/pr3"].stateValues.text.replace(/, /g, "")).eq( + rs.join(""), + ); + expect(stateVariables["/ps3"].stateValues.text.replace(/, /g, "")).eq( + ss.join(""), + ); + + expect(stateVariables["/pq4"].stateValues.text.replace(/, /g, "")).eq( + qs.join(""), + ); + expect(stateVariables["/pr4"].stateValues.text.replace(/, /g, "")).eq( + rs.join(""), + ); + expect(stateVariables["/ps4"].stateValues.text.replace(/, /g, "")).eq( + ss.join(""), + ); + }); + + it("references to select of selects of selects, newnamespaces", async () => { + let core = await createTestCore({ + doenetML: ` + + + + + + + + + + + +

Selected options repeated

+

$(a/q{name="q2"})

+

$(a/r{name="r2"})

+

$(a/s{name="s2"})

+ +

Copy x/q, x/r, x/s

+

$(a/q/q{name="qq"})$(a/q/r{name="qr"})$(a/q/s{name="qs"})

+

$(a/r/q{name="rq"})$(a/r/r{name="rr"})$(a/r/s{name="rs"})

+

$(a/s/q{name="sq"})$(a/s/r{name="sr"})$(a/s/s{name="ss"})

+ +

Copy x/x/q, x/x/r

+

$(a/q/q/q{name="qqq"})$(a/q/q/r{name="qqr"})$(a/q/r/q{name="qrq"})$(a/q/r/r{name="qrr"})$(a/q/s/q{name="qsq"})$(a/q/s/r{name="qsr"})

+

$(a/r/q/q{name="rqq"})$(a/r/q/r{name="rqr"})$(a/r/r/q{name="rrq"})$(a/r/r/r{name="rrr"})$(a/r/s/q{name="rsq"})$(a/r/s/r{name="rsr"})

+

$(a/s/q/q{name="sqq"})$(a/s/q/r{name="sqr"})$(a/s/r/q{name="srq"})$(a/s/r/r{name="srr"})$(a/s/s/q{name="ssq"})$(a/s/s/r{name="ssr"})

+ + `, + }); + + let stateVariables = await returnAllStateVariables(core); + let qs = [ + "/a/q/q/q", + "/a/q/q/r", + "/a/q/r/q", + "/a/q/r/r", + "/a/q/s/q", + "/a/q/s/r", + ].map((x) => + stateVariables[x].replacements + ? stateVariables[ + stateVariables[x].replacements[0].componentName + ].stateValues.value + : stateVariables[x].stateValues.value, + ); + let rs = [ + "/a/r/q/q", + "/a/r/q/r", + "/a/r/r/q", + "/a/r/r/r", + "/a/r/s/q", + "/a/r/s/r", + ].map((x) => + stateVariables[x].replacements + ? stateVariables[ + stateVariables[x].replacements[0].componentName + ].stateValues.value + : stateVariables[x].stateValues.value, + ); + let ss = [ + "/a/s/q/q", + "/a/s/q/r", + "/a/s/r/q", + "/a/s/r/r", + "/a/s/s/q", + "/a/s/s/r", + ].map((x) => + stateVariables[x].replacements + ? stateVariables[ + stateVariables[x].replacements[0].componentName + ].stateValues.value + : stateVariables[x].stateValues.value, + ); + + expect(stateVariables["/pq2"].stateValues.text.replace(/, /g, "")).eq( + qs.join(""), + ); + expect(stateVariables["/pr2"].stateValues.text.replace(/, /g, "")).eq( + rs.join(""), + ); + expect(stateVariables["/ps2"].stateValues.text.replace(/, /g, "")).eq( + ss.join(""), + ); + + expect(stateVariables["/pq3"].stateValues.text.replace(/, /g, "")).eq( + qs.join(""), + ); + expect(stateVariables["/pr3"].stateValues.text.replace(/, /g, "")).eq( + rs.join(""), + ); + expect(stateVariables["/ps3"].stateValues.text.replace(/, /g, "")).eq( + ss.join(""), + ); + + expect(stateVariables["/pq4"].stateValues.text.replace(/, /g, "")).eq( + qs.join(""), + ); + expect(stateVariables["/pr4"].stateValues.text.replace(/, /g, "")).eq( + rs.join(""), + ); + expect(stateVariables["/ps4"].stateValues.text.replace(/, /g, "")).eq( + ss.join(""), + ); + }); + + it("references to named grandchildren's children", async () => { + let core = await createTestCore({ + doenetML: ` + + +

Copy grandchidren

+

$a{name="a2"}

+

$b{name="b2"}

+

$c{name="c2"}

+

$d{name="d2"}

+ +

Copy named children of grandchild

+

$(a/w{name="w2"})

+

$(b/v{name="v2"})

+ + `, + }); + + let options = [ + { + a: "x y", + b: "3 z", + c: "x", + d: "z", + v: "z", + w: "x", + }, + { + a: "u v", + b: "3 t", + c: "u", + d: "t", + v: "t", + w: "u", + }, + ]; + + let stateVariables = await returnAllStateVariables(core); + + let chosenChildren = stateVariables[ + stateVariables["/_select1"].replacements![0].componentName + ] + .replacements!.filter((x) => typeof x !== "string") + .map((x) => stateVariables[x.componentName]) + .map((v, i) => + i < 2 ? v : stateVariables[v.replacements![0].componentName], + ); + let option = + options[ + stateVariables["/_select1"].stateValues.selectedIndices[0] - 1 + ]; + + expect(me.fromAst(chosenChildren[0].stateValues.value).toString()).eq( + option.a, + ); + expect(me.fromAst(chosenChildren[1].stateValues.value).toString()).eq( + option.b, + ); + expect(me.fromAst(chosenChildren[2].stateValues.value).toString()).eq( + option.c, + ); + expect(me.fromAst(chosenChildren[3].stateValues.value).toString()).eq( + option.d, + ); + + let a2 = me.fromAst(stateVariables["/a2"].stateValues.value).toString(); + let b2 = me.fromAst(stateVariables["/b2"].stateValues.value).toString(); + let c2 = me.fromAst(stateVariables["/c2"].stateValues.value).toString(); + let d2 = me.fromAst(stateVariables["/d2"].stateValues.value).toString(); + let v2 = me.fromAst(stateVariables["/v2"].stateValues.value).toString(); + let w2 = me.fromAst(stateVariables["/w2"].stateValues.value).toString(); + + expect(a2).eq(option.a); + expect(b2).eq(option.b); + expect(c2).eq(option.c); + expect(d2).eq(option.d); + expect(v2).eq(option.v); + expect(w2).eq(option.w); + }); + + it("select of a map of a select, with references", async () => { + let core = await createTestCore({ + doenetML: ` +

+ +

+ +

Copy whole select again

+

$_select1{name="s2"}

+ +

Copy individual selections

+

+ $j{name="j2"} + $k{name="k2"} + $l{name="l2"} +

+ +

Copy individual pieces

+

+ $(j/a/p{name="p1"})$(j/a/q{name="p2"})$(j/a/r{name="p3"})$(j/a/s{name="p4"})$(j/b/p{name="p5"})$(j/b/q{name="p6"})$(j/b/r{name="p7"})$(j/b/s{name="p8"}) + $(k/a/p{name="p9"})$(k/a/q{name="p10"})$(k/a/r{name="p11"})$(k/a/s{name="p12"})$(k/b/p{name="p13"})$(k/b/q{name="p14"})$(k/b/r{name="p15"})$(k/b/s{name="p16"}) + $(l/a/p{name="p17"})$(l/a/q{name="p18"})$(l/a/r{name="p19"})$(l/a/s{name="p20"})$(l/b/p{name="p21"})$(l/b/q{name="p22"})$(l/b/r{name="p23"})$(l/b/s{name="p24"}) +

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + + let theList1 = stateVariables["/list1"].activeChildren.map((x) => + me + .fromAst(stateVariables[x.componentName].stateValues.value) + .toString(), + ); + let theList2 = stateVariables["/list2"].activeChildren.map((x) => + me + .fromAst(stateVariables[x.componentName].stateValues.value) + .toString(), + ); + let theList3 = stateVariables["/list3"].activeChildren.map((x) => + me + .fromAst(stateVariables[x.componentName].stateValues.value) + .toString(), + ); + + expect(theList2).eqls(theList1); + expect(theList3).eqls(theList1); + + let theList4 = [...Array(24).keys()].map((i) => + me + .fromAst(stateVariables["/p" + (i + 1)].stateValues.value) + .toString(), + ); + + expect(theList4).eqls(theList1); + }); + + it("select of a map of a select, new namespaces", async () => { + let core = await createTestCore({ + doenetML: ` +

+ +

+ +

Copy whole select again

+

$s{name="s2"}

+ +

Copy individual selections

+

+ $(s/j{name="j2"}) + $(s/k{name="k2"}) + $(s/l{name="l2"}) +

+ +

Copy individual pieces

+

+ $(s/j/a/v/p{name="p1"})$(s/j/a/v/q{name="p2"})$(s/j/a/v/r{name="p3"})$(s/j/a/v/s{name="p4"})$(s/j/b/v/p{name="p5"})$(s/j/b/v/q{name="p6"})$(s/j/b/v/r{name="p7"})$(s/j/b/v/s{name="p8"}) + $(s/k/a/v/p{name="p9"})$(s/k/a/v/q{name="p10"})$(s/k/a/v/r{name="p11"})$(s/k/a/v/s{name="p12"})$(s/k/b/v/p{name="p13"})$(s/k/b/v/q{name="p14"})$(s/k/b/v/r{name="p15"})$(s/k/b/v/s{name="p16"}) + $(s/l/a/v/p{name="p17"})$(s/l/a/v/q{name="p18"})$(s/l/a/v/r{name="p19"})$(s/l/a/v/s{name="p20"})$(s/l/b/v/p{name="p21"})$(s/l/b/v/q{name="p22"})$(s/l/b/v/r{name="p23"})$(s/l/b/v/s{name="p24"}) +

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + + let theList1 = stateVariables["/list1"].activeChildren.map((x) => + me + .fromAst(stateVariables[x.componentName].stateValues.value) + .toString(), + ); + let theList2 = stateVariables["/list2"].activeChildren.map((x) => + me + .fromAst(stateVariables[x.componentName].stateValues.value) + .toString(), + ); + let theList3 = stateVariables["/list3"].activeChildren.map((x) => + me + .fromAst(stateVariables[x.componentName].stateValues.value) + .toString(), + ); + + expect(theList2).eqls(theList1); + expect(theList3).eqls(theList1); + + let theList4 = [...Array(24).keys()].map((i) => + me + .fromAst(stateVariables["/p" + (i + 1)].stateValues.value) + .toString(), + ); + + expect(theList4).eqls(theList1); + }); + + // Note: this test encodes undesired behavior (see issue #246) + // When this issue is resolved, change this test to make sure the references + // are hidden when the select is hidden + it("select with hide will hide replacements but not copies", async () => { + let core = await createTestCore({ + doenetML: ` +

Selects and hide

+

,

+

$c, $d

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + let c = await stateVariables["/c"].stateValues.value; + let d = await stateVariables["/d"].stateValues.value; + expect(["a", "b", "c", "d", "e"].includes(c)).eq(true); + expect(["a", "b", "c", "d", "e"].includes(d)).eq(true); + + expect(stateVariables["/p1"].stateValues.text).eq(`${c}, `); + expect(stateVariables["/p2"].stateValues.text).eq(`${c}, ${d}`); + }); + + // Note: this test encodes undesired behavior (see issue #246) + // When this issue is resolved, change this test to make sure the references + // are hidden when the select is hidden + it("select with hide will hide named grandchildren replacements but not copies", async () => { + let core = await createTestCore({ + doenetML: ` +

Selects and hide

+

+

$a, , $c, , $e

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + let a = stateVariables["/a"].stateValues.value; + let b = stateVariables["/b"].stateValues.value; + let c = stateVariables["/c"].stateValues.value; + let d = stateVariables["/d"].stateValues.value; + let e = stateVariables["/e"].stateValues.value; + expect(["a", "d"].includes(a)).eq(true); + expect(["b", "e"].includes(b)).eq(true); + expect(["c", "f"].includes(c)).eq(true); + expect(["a", "c", "e"].includes(d)).eq(true); + expect(["b", "d", "f"].includes(e)).eq(true); + + expect(stateVariables["/p1"].stateValues.text).eq(`${a}, ${b}, ${c}`); + expect(stateVariables["/p2"].stateValues.text).eq( + `${a}, , ${c}, ${d}, ${e}`, + ); + }); + + // Note: this test encodes undesired behavior (see issue #246) + // When this issue is resolved, change this test to make sure the references + // are hidden when the select is hidden + it("select with hide will hide named grandchildren replacements but not copies", async () => { + let core = await createTestCore({ + doenetML: ` +

Selects and hide

+

+

$a, , $c, , $e

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + let a = stateVariables["/a"].stateValues.value; + let b = stateVariables["/b"].stateValues.value; + let c = stateVariables["/c"].stateValues.value; + let d = stateVariables["/d"].stateValues.value; + let e = stateVariables["/e"].stateValues.value; + expect(["a", "d"].includes(a)).eq(true); + expect(["b", "e"].includes(b)).eq(true); + expect(["c", "f"].includes(c)).eq(true); + expect(["a", "c", "e"].includes(d)).eq(true); + expect(["b", "d", "f"].includes(e)).eq(true); + + expect(stateVariables["/p1"].stateValues.text).eq(`${a}, ${b}, ${c}`); + expect(stateVariables["/p2"].stateValues.text).eq( + `${a}, , ${c}, ${d}, ${e}`, + ); + }); + + // Note: this test encodes undesired behavior (see issue #246) + // When this issue is resolved, change this test to make sure the references + // are hidden when the select is hidden + it("selects hide dynamically", async () => { + let core = await createTestCore({ + doenetML: ` + + + + + + +

,

+

$c, $d

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + let c = await stateVariables["/c"].stateValues.value; + let d = await stateVariables["/d"].stateValues.value; + expect(["a", "b", "c", "d", "e"].includes(c)).eq(true); + expect(["a", "b", "c", "d", "e"].includes(d)).eq(true); + + stateVariables = await returnAllStateVariables(core); + expect(stateVariables["/p1"].stateValues.text).eq(`${c}, `); + expect(stateVariables["/p2"].stateValues.text).eq(`${c}, ${d}`); + + await updateBooleanInputValue({ + boolean: true, + componentName: "/h1", + core, + }); + await updateBooleanInputValue({ + boolean: false, + componentName: "/h2", + core, + }); + + stateVariables = await returnAllStateVariables(core); + expect(stateVariables["/p1"].stateValues.text).eq(`, ${d}`); + expect(stateVariables["/p2"].stateValues.text).eq(`${c}, ${d}`); + + await updateBooleanInputValue({ + boolean: false, + componentName: "/h1", + core, + }); + await updateBooleanInputValue({ + boolean: true, + componentName: "/h2", + core, + }); + + stateVariables = await returnAllStateVariables(core); + expect(stateVariables["/p1"].stateValues.text).eq(`${c}, `); + expect(stateVariables["/p2"].stateValues.text).eq(`${c}, ${d}`); + }); + + it("string and blank strings in options", async () => { + let core = await createTestCore({ + doenetML: ` + + foxjumps + elephanttrumpets + + +

a:

+ +

a1: $a{assignNames="a11 a12 a13 a14"}

+ +

pieces: +

q,r =

+ + +

q2 = $q

+

r2 = $r

+ + + + `, + }); + + let stateVariables = await returnAllStateVariables(core); + + let replacements = + stateVariables[ + stateVariables["/select1"].replacements![0].componentName + ].replacements!; + + let p1 = replacements[1].componentName; + let p2 = replacements[3].componentName; + let p3 = replacements[5].componentName; + + expect(stateVariables[p1].stateValues.text).eq(`q,r = ab`); + expect(stateVariables[p2].stateValues.text).eq(`q2 = a`); + expect(stateVariables[p3].stateValues.text).eq(`r2 = b`); + }); + + it("display error when miss a name in selectForVariants, inside text", async () => { + let core = await createTestCore({ + doenetML: ` + + +

We have a !

+ `, + }); + + let errorWarnings = core.errorWarnings; + + expect(errorWarnings.errors.length).eq(1); + expect(errorWarnings.warnings.length).eq(0); + + expect(errorWarnings.errors[0].message).contain( + "Some variants are specified for select but no options are specified for possible variant name: banana", + ); + expect(errorWarnings.errors[0].doenetMLrange.lineBegin).eq(4); + expect(errorWarnings.errors[0].doenetMLrange.charBegin).eq(24); + expect(errorWarnings.errors[0].doenetMLrange.lineEnd).eq(7); + expect(errorWarnings.errors[0].doenetMLrange.charEnd).eq(13); + }); + + it("display error when repeat name in selectForVariants more times than numToSelect, inside p", async () => { + let core = await createTestCore({ + doenetML: ` + + +

We have a !

+ `, + }); + + let errorWarnings = core.errorWarnings; + + expect(errorWarnings.errors.length).eq(1); + expect(errorWarnings.warnings.length).eq(0); + + expect(errorWarnings.errors[0].message).contain( + "Invalid variant name for select. Variant name apple appears in 2 options but number to select is 1", + ); + expect(errorWarnings.errors[0].doenetMLrange.lineBegin).eq(4); + expect(errorWarnings.errors[0].doenetMLrange.charBegin).eq(18); + expect(errorWarnings.errors[0].doenetMLrange.lineEnd).eq(7); + expect(errorWarnings.errors[0].doenetMLrange.charEnd).eq(13); + }); + + it("display error when repeat name in selectForVariants more times than numToSelect, inside document", async () => { + let core = await createTestCore({ + doenetML: ` + + + We have a ! + `, + }); + + let errorWarnings = core.errorWarnings; + + expect(errorWarnings.errors.length).eq(1); + expect(errorWarnings.warnings.length).eq(0); + + expect(errorWarnings.errors[0].message).contain( + "Variant name donut that is specified for select is not a possible variant name", + ); + expect(errorWarnings.errors[0].doenetMLrange.lineBegin).eq(4); + expect(errorWarnings.errors[0].doenetMLrange.charBegin).eq(15); + expect(errorWarnings.errors[0].doenetMLrange.lineEnd).eq(8); + expect(errorWarnings.errors[0].doenetMLrange.charEnd).eq(13); + }); + + it("display error when numToSelect is larger than number of options, inside graph", async () => { + let core = await createTestCore({ + doenetML: ` +

No points for graph!

+ + + `, + }); + + let errorWarnings = core.errorWarnings; + + expect(errorWarnings.errors.length).eq(1); + expect(errorWarnings.warnings.length).eq(0); + + expect(errorWarnings.errors[0].message).contain( + "Cannot select 3 components from only 2", + ); + expect(errorWarnings.errors[0].doenetMLrange.lineBegin).eq(4); + expect(errorWarnings.errors[0].doenetMLrange.charBegin).eq(12); + expect(errorWarnings.errors[0].doenetMLrange.lineEnd).eq(7); + expect(errorWarnings.errors[0].doenetMLrange.charEnd).eq(13); + }); + + it("numToSelect from selectFromSequence", async () => { + let core = await createTestCore({ + doenetML: ` +

n1 =

+

vars =

+

a1=$a1, b1=$b1, c1=$c1, d1=$d1, e1=$e1

+ +

n2 =

+

vars =

+

a2=$a2, b2=$b2, c2=$c2, d2=$d2, e2=$e2

+ +

n3 =

+

vars =

+

a3=$a3, b3=$b3, c3=$c3, d3=$d3, e3=$e3

+ +

n4 =

+

vars =

+

a4=$a4, b4=$b4, c4=$c4, d4=$d4, e4=$e4

+ +

n5 =

+

vars =

+

a5=$a5, b5=$b5, c5=$c5, d5=$d5, e5=$e5

+ `, + }); + + let stateVariables = await returnAllStateVariables(core); + let n1 = stateVariables["/n1"].stateValues.value; + let n2 = stateVariables["/n2"].stateValues.value; + let n3 = stateVariables["/n3"].stateValues.value; + let n4 = stateVariables["/n4"].stateValues.value; + let n5 = stateVariables["/n5"].stateValues.value; + + let vars1 = stateVariables["/vars1"].replacements!.map( + (x) => + stateVariables[ + stateVariables[x.componentName].replacements![0] + .componentName + ].stateValues.value, + ); + let vars2 = stateVariables["/vars2"].replacements!.map( + (x) => + stateVariables[ + stateVariables[x.componentName].replacements![0] + .componentName + ].stateValues.value, + ); + let vars3 = stateVariables["/vars3"].replacements!.map( + (x) => + stateVariables[ + stateVariables[x.componentName].replacements![0] + .componentName + ].stateValues.value, + ); + let vars4 = stateVariables["/vars4"].replacements!.map( + (x) => + stateVariables[ + stateVariables[x.componentName].replacements![0] + .componentName + ].stateValues.value, + ); + let vars5 = stateVariables["/vars5"].replacements!.map( + (x) => + stateVariables[ + stateVariables[x.componentName].replacements![0] + .componentName + ].stateValues.value, + ); + + expect(vars1.length).eq(n1); + expect(vars2.length).eq(n2); + expect(vars3.length).eq(n3); + expect(vars4.length).eq(n4); + expect(vars5.length).eq(n5); + + vars1.length = 5; + vars2.length = 5; + vars3.length = 5; + vars4.length = 5; + vars5.length = 5; + + vars1.fill("", n1); + vars2.fill("", n2); + vars3.fill("", n3); + vars4.fill("", n4); + vars5.fill("", n5); + + let l = ["a", "b", "c", "d", "e"]; + + expect(stateVariables["/p1"].stateValues.text).eq( + vars1.map((v, i) => `${l[i]}1=${v}`).join(", "), + ); + expect(stateVariables["/p2"].stateValues.text).eq( + vars2.map((v, i) => `${l[i]}2=${v}`).join(", "), + ); + expect(stateVariables["/p3"].stateValues.text).eq( + vars3.map((v, i) => `${l[i]}3=${v}`).join(", "), + ); + expect(stateVariables["/p4"].stateValues.text).eq( + vars4.map((v, i) => `${l[i]}4=${v}`).join(", "), + ); + expect(stateVariables["/p5"].stateValues.text).eq( + vars5.map((v, i) => `${l[i]}5=${v}`).join(", "), + ); + }); + + it("add level to assign names even in shadow", async () => { + let core = await createTestCore({ + doenetML: ` +

+ + `, + }); + + let stateVariables = await returnAllStateVariables(core); + + let q = stateVariables["/q"].stateValues.value.tree; + + expect(stateVariables["/c/q"].stateValues.value.tree).eq(q); + }); + + it("ensure unique names", async () => { + let core = await createTestCore({ + doenetML: ` + + + + + + `, + }); + + let stateVariables = await returnAllStateVariables(core); + + let pNames1 = stateVariables["/_select1"].replacements!.map( + (x) => + stateVariables[x.componentName].replacements![0].componentName, + ); + for (let pn of pNames1) { + expect(stateVariables[pn].stateValues.text).eq("What is this?"); + } + + let pNames2 = ["/A", "/B", "/C"].map( + (x) => stateVariables[x].replacements![0].componentName, + ); + for (let pn of pNames2) { + expect(stateVariables[pn].stateValues.text).eq("What is this?"); + } + + for (let pn of ["/D", "/E", "/F"]) { + expect(stateVariables[pn].stateValues.text).eq("What is this?"); + } + }); +}); diff --git a/packages/test-cypress/cypress/e2e/tagSpecific/select.cy.js b/packages/test-cypress/cypress/e2e/tagSpecific/select.cy.js index 795e9ef27..b566769ee 100644 --- a/packages/test-cypress/cypress/e2e/tagSpecific/select.cy.js +++ b/packages/test-cypress/cypress/e2e/tagSpecific/select.cy.js @@ -1,5 +1,4 @@ -import me from "math-expressions"; -import { cesc, cesc2 } from "@doenet/utils"; +import { cesc2 } from "@doenet/utils"; describe("Select Tag Tests", function () { beforeEach(() => { @@ -7,476 +6,6 @@ describe("Select Tag Tests", function () { cy.visit("/"); }); - it("no parameters, select doesn't do anything", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a -

- - - - - - - - - - - - - - - - - - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait until loaded - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - for (let ind = 1; ind <= 10; ind++) { - let x = stateVariables["/x" + ind].stateValues.value; - expect(["u", "v", "w", "x", "y", "z"].includes(x)).eq(true); - } - }); - }); - - it("select multiple maths", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait until loaded - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - for (let ind = 1; ind <= 5; ind++) { - let x = stateVariables["/x" + ind].stateValues.value; - let y = stateVariables["/y" + ind].stateValues.value; - let z = stateVariables["/z" + ind].stateValues.value; - - expect(["u", "v", "w", "x", "y", "z"].includes(x)).eq(true); - expect(["u", "v", "w", "x", "y", "z"].includes(y)).eq(true); - expect(["u", "v", "w", "x", "y", "z"].includes(z)).eq(true); - expect(x).not.eq(y); - expect(x).not.eq(z); - expect(y).not.eq(z); - } - }); - }); - - it("select multiple maths, initially unresolved", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - - - $n3{name="n2"} - $num1{name="n"} - $n2+$num2 - $n3+$num3 - $num3{name="n3"} - 1 - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - cy.get(cesc("#\\/num1") + " .mjx-mrow") - .eq(0) - .invoke("text") - .then((text) => { - expect(text.trim()).equal("3"); - }); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - for (let ind = 1; ind <= 5; ind++) { - let x = stateVariables["/x" + ind].stateValues.value; - let y = stateVariables["/y" + ind].stateValues.value; - let z = stateVariables["/z" + ind].stateValues.value; - - expect(["u", "v", "w", "x", "y", "z"].includes(x)).eq(true); - expect(["u", "v", "w", "x", "y", "z"].includes(y)).eq(true); - expect(["u", "v", "w", "x", "y", "z"].includes(z)).eq(true); - expect(x).not.eq(y); - expect(x).not.eq(z); - expect(y).not.eq(z); - } - }); - }); - - it("select multiple maths with namespace", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait until loaded - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - for (let ind = 1; ind <= 5; ind++) { - let x = - stateVariables["/s" + ind + "/x" + ind].stateValues.value; - let y = - stateVariables["/s" + ind + "/y" + ind].stateValues.value; - let z = - stateVariables["/s" + ind + "/z" + ind].stateValues.value; - - expect(["u", "v", "w", "x", "y", "z"].includes(x)).eq(true); - expect(["u", "v", "w", "x", "y", "z"].includes(y)).eq(true); - expect(["u", "v", "w", "x", "y", "z"].includes(z)).eq(true); - expect(x).not.eq(y); - expect(x).not.eq(z); - expect(y).not.eq(z); - } - }); - }); - - it("select multiple maths, with replacement", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait until loaded - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - for (let ind = 1; ind <= 5; ind++) { - let x = stateVariables["/x" + ind].stateValues.value; - let y = stateVariables["/y" + ind].stateValues.value; - let z = stateVariables["/z" + ind].stateValues.value; - - expect(["x", "y", "z"].includes(x)).eq(true); - expect(["x", "y", "z"].includes(y)).eq(true); - expect(["x", "y", "z"].includes(z)).eq(true); - - let s = stateVariables["/s" + ind]; - - for (let i = 3; i < 5; i++) { - expect( - ["x", "y", "z"].includes( - stateVariables[ - stateVariables[s.replacements[i].componentName] - .replacements[0].componentName - ].stateValues.value, - ), - ).eq(true); - } - } - }); - }); - - it("asList", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a -

-

- - - - - - - - - -

- -

- - $s1{name="noresample1"} - $s2{name="noresample2"} - $noresample1{name="noreresample1"} - $noresample2{name="noreresample2"} - -

- -

- $_aslist1{name="noresamplelist"} -

- -

- $noresamplelist{name="noreresamplelist"} -

- - $_p1{name="noresamplep"} - $noresamplep{name="noreresamplep"} - - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait until loaded - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let x1 = - stateVariables[ - stateVariables[ - stateVariables["/s1"].replacements[0].componentName - ].replacements[0].componentName - ].stateValues.value; - let x2 = - stateVariables[ - stateVariables[ - stateVariables["/s2"].replacements[0].componentName - ].replacements[0].componentName - ].stateValues.value; - expect(["u", "v", "w", "x", "y", "z"].includes(x1)).eq(true); - expect(["u", "v", "w", "x", "y", "z"].includes(x2)).eq(true); - - expect( - stateVariables[ - stateVariables[ - stateVariables["/noresample1"].replacements[0] - .componentName - ].replacements[0].componentName - ].stateValues.value, - ).eq(x1); - expect( - stateVariables[ - stateVariables[ - stateVariables["/noresample2"].replacements[0] - .componentName - ].replacements[0].componentName - ].stateValues.value, - ).eq(x2); - expect( - stateVariables[ - stateVariables[ - stateVariables["/noreresample1"].replacements[0] - .componentName - ].replacements[0].componentName - ].stateValues.value, - ).eq(x1); - expect( - stateVariables[ - stateVariables[ - stateVariables["/noreresample2"].replacements[0] - .componentName - ].replacements[0].componentName - ].stateValues.value, - ).eq(x2); - - expect( - stateVariables[ - stateVariables["/noresamplelist"].activeChildren[0] - .componentName - ].stateValues.value, - ).eq(x1); - expect( - stateVariables[ - stateVariables["/noresamplelist"].activeChildren[1] - .componentName - ].stateValues.value, - ).eq(x2); - expect( - stateVariables[ - stateVariables["/noreresamplelist"].activeChildren[0] - .componentName - ].stateValues.value, - ).eq(x1); - expect( - stateVariables[ - stateVariables["/noreresamplelist"].activeChildren[1] - .componentName - ].stateValues.value, - ).eq(x2); - - expect( - stateVariables[ - stateVariables[ - stateVariables["/noresamplep"].activeChildren[1] - .componentName - ].activeChildren[0].componentName - ].stateValues.value, - ).eq(x1); - expect( - stateVariables[ - stateVariables[ - stateVariables["/noresamplep"].activeChildren[1] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ).eq(x2); - expect( - stateVariables[ - stateVariables[ - stateVariables["/noreresamplep"].activeChildren[1] - .componentName - ].activeChildren[0].componentName - ].stateValues.value, - ).eq(x1); - expect( - stateVariables[ - stateVariables[ - stateVariables["/noreresamplep"].activeChildren[1] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ).eq(x2); - }); - }); - - it("select doesn't change dynamically", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a -

Number to select:

-

First option:

-

Second option:

-

Third option:

-

- Selected choices: - - -

- -

Selected choices: - - - - -

-

-

-

$x1$y1$z1

-

$x2$y2$z2

-

$x3$y3$z3

- `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_math1") + " .mjx-mrow") - .eq(0) - .invoke("text") - .then((text) => { - expect(text.trim()).equal("1"); - }); - - let lists = { - x: ["x", "y", "z"], - u: ["u", "v", "w"], - a: ["a", "b", "c"], - q: ["q", "r", "s"], - }; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let x1 = stateVariables["/x1"].stateValues.value; - let y1 = stateVariables["/y1"].stateValues.value; - let z1 = stateVariables["/z1"].stateValues.value; - let x2 = stateVariables["/x2"].stateValues.value; - let y2 = stateVariables["/y2"].stateValues.value; - let z2 = stateVariables["/z2"].stateValues.value; - let x3 = stateVariables["/x3"].stateValues.value; - let y3 = stateVariables["/y3"].stateValues.value; - let z3 = stateVariables["/z3"].stateValues.value; - - let list1 = lists[x1]; - let list2 = lists[x2]; - let list3 = lists[x3]; - - expect(y1).eq(list1[1]); - expect(z1).eq(list1[2]); - expect(y2).eq(list2[1]); - expect(z2).eq(list2[2]); - expect(y3).eq(list3[1]); - expect(z3).eq(list3[2]); - - for (let name of ["/p1", "/q1"]) { - let aslistChildren = stateVariables[ - stateVariables[name].activeChildren[0].componentName - ].activeChildren.map((x) => stateVariables[x.componentName]); - for (let ind = 0; ind < 3; ind++) { - expect(aslistChildren[ind].stateValues.value).eq( - list1[ind], - ); - } - } - for (let name of ["/p2", "/q2"]) { - let aslistChildren = stateVariables[ - stateVariables[name].activeChildren[0].componentName - ].activeChildren.map((x) => stateVariables[x.componentName]); - for (let ind = 0; ind < 3; ind++) { - expect(aslistChildren[ind].stateValues.value).eq( - list2[ind], - ); - } - } - for (let name of ["/p3", "/q3"]) { - let aslistChildren = stateVariables[ - stateVariables[name].activeChildren[0].componentName - ].activeChildren.map((x) => stateVariables[x.componentName]); - for (let ind = 0; ind < 3; ind++) { - expect(aslistChildren[ind].stateValues.value).eq( - list3[ind], - ); - } - } - }); - }); - - it("select single group of maths, assign names with namespace to grandchildren", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - 1 -

-

-

-

$(s1/x)$(s1/y)$(s1/z)

-

$(s2/x)$(s2/y)$(s2/z)

-

$(s3/x)$(s3/y)$(s3/z)

- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_math1") + " .mjx-mrow") - .eq(0) - .invoke("text") - .then((text) => { - expect(text.trim()).equal("1"); - }); - - let lists = { - x: ["x", "y", "z"], - u: ["u", "v", "w"], - a: ["a", "b", "c"], - q: ["q", "r", "s"], - }; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let x1 = stateVariables["/s1/x"].stateValues.value; - let y1 = stateVariables["/s1/y"].stateValues.value; - let z1 = stateVariables["/s1/z"].stateValues.value; - let x2 = stateVariables["/s2/x"].stateValues.value; - let y2 = stateVariables["/s2/y"].stateValues.value; - let z2 = stateVariables["/s2/z"].stateValues.value; - let x3 = stateVariables["/s3/x"].stateValues.value; - let y3 = stateVariables["/s3/y"].stateValues.value; - let z3 = stateVariables["/s3/z"].stateValues.value; - - let list1 = lists[x1]; - let list2 = lists[x2]; - let list3 = lists[x3]; - - expect(y1).eq(list1[1]); - expect(z1).eq(list1[2]); - expect(y2).eq(list2[1]); - expect(z2).eq(list2[2]); - expect(y3).eq(list3[1]); - expect(z3).eq(list3[2]); - - for (let name of ["/p1", "/q1"]) { - let aslistChildren = stateVariables[ - stateVariables[name].activeChildren[0].componentName - ].activeChildren.map((x) => stateVariables[x.componentName]); - for (let ind = 0; ind < 3; ind++) { - expect(aslistChildren[ind].stateValues.value).eq( - list1[ind], - ); - } - } - for (let name of ["/p2", "/q2"]) { - let aslistChildren = stateVariables[ - stateVariables[name].activeChildren[0].componentName - ].activeChildren.map((x) => stateVariables[x.componentName]); - for (let ind = 0; ind < 3; ind++) { - expect(aslistChildren[ind].stateValues.value).eq( - list2[ind], - ); - } - } - for (let name of ["/p3", "/q3"]) { - let aslistChildren = stateVariables[ - stateVariables[name].activeChildren[0].componentName - ].activeChildren.map((x) => stateVariables[x.componentName]); - for (let ind = 0; ind < 3; ind++) { - expect(aslistChildren[ind].stateValues.value).eq( - list3[ind], - ); - } - } - }); - }); - - it("select multiple group of maths, assign names to grandchildren", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - 1 -

- -

-

- $x1$y1$z1 - $x2$y2$z2 - $x3$y3$z3 -

- `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_math1") + " .mjx-mrow") - .eq(0) - .invoke("text") - .then((text) => { - expect(text.trim()).equal("1"); - }); - - let lists = { - x: ["x", "y", "z"], - u: ["u", "v", "w"], - a: ["a", "b", "c"], - q: ["q", "r", "s"], - }; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let x1 = stateVariables["/x1"].stateValues.value; - let y1 = stateVariables["/y1"].stateValues.value; - let z1 = stateVariables["/z1"].stateValues.value; - let x2 = stateVariables["/x2"].stateValues.value; - let y2 = stateVariables["/y2"].stateValues.value; - let z2 = stateVariables["/z2"].stateValues.value; - let x3 = stateVariables["/x3"].stateValues.value; - let y3 = stateVariables["/y3"].stateValues.value; - let z3 = stateVariables["/z3"].stateValues.value; - - let list1 = lists[x1]; - let list2 = lists[x2]; - let list3 = lists[x3]; - - let listsByInd = [list1, list2, list3]; - - expect(x1).not.eq(x2); - expect(x1).not.eq(x3); - expect(x2).not.eq(x3); - - expect(y1).eq(list1[1]); - expect(z1).eq(list1[2]); - expect(y2).eq(list2[1]); - expect(z2).eq(list2[2]); - expect(y3).eq(list3[1]); - expect(z3).eq(list3[2]); - - for (let name of ["/p1", "/q1"]) { - let aslistChildren = stateVariables[ - stateVariables[name].activeChildren[0].componentName - ].activeChildren.map((x) => stateVariables[x.componentName]); - for (let ind1 = 0; ind1 < 3; ind1++) { - for (let ind2 = 0; ind2 < 3; ind2++) { - expect( - aslistChildren[ind1 * 3 + ind2].stateValues.value, - ).eq(listsByInd[ind1][ind2]); - } - } - } - }); - }); - - it("references to outside components", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - 1 - x - y - z - - - - a - b - c - -

Selected options repeated

- $q{name="q2"} - $r{name="r2"} - $s{name="s2"} - $t{name="t2"} - $u{name="u2"} - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_math1") + " .mjx-mrow") - .eq(0) - .invoke("text") - .then((text) => { - expect(text.trim()).equal("1"); - }); - - let option = { - "Option 1: ": me.fromText("3xa"), - "Option 2: ": me.fromText("4yb"), - "Option 3: ": me.fromText("5zc"), - }; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let q2 = - stateVariables[ - stateVariables["/q2"].replacements[0].componentName - ].activeChildren; - let q2string = q2[0]; - let q2math = me.fromAst( - stateVariables[q2[1].componentName].stateValues.value, - ); - expect(q2math.equals(option[q2string])).eq(true); - - let r2 = - stateVariables[ - stateVariables["/r2"].replacements[0].componentName - ].activeChildren; - let r2string = r2[0]; - let r2math = me.fromAst( - stateVariables[r2[1].componentName].stateValues.value, - ); - expect(r2math.equals(option[r2string])).eq(true); - - let s2 = - stateVariables[ - stateVariables["/s2"].replacements[0].componentName - ].activeChildren; - let s2string = s2[0]; - let s2math = me.fromAst( - stateVariables[s2[1].componentName].stateValues.value, - ); - expect(s2math.equals(option[s2string])).eq(true); - - let t2 = - stateVariables[ - stateVariables["/t2"].replacements[0].componentName - ].activeChildren; - let t2string = t2[0]; - let t2math = me.fromAst( - stateVariables[t2[1].componentName].stateValues.value, - ); - expect(t2math.equals(option[t2string])).eq(true); - - let u2 = - stateVariables[ - stateVariables["/u2"].replacements[0].componentName - ].activeChildren; - let u2string = u2[0]; - let u2math = me.fromAst( - stateVariables[u2[1].componentName].stateValues.value, - ); - expect(u2math.equals(option[u2string])).eq(true); - }); - }); - - it("references to outside components, no new namespace", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - 1 - x - y - z - - - - a - b - c - -

Selected options repeated

- $q{name="q2"} - $r{name="r2"} - $s{name="s2"} - $t{name="t2"} - $u{name="u2"} - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_math1") + " .mjx-mrow") - .eq(0) - .invoke("text") - .then((text) => { - expect(text.trim()).equal("1"); - }); - - let option = { - "Option 1: ": me.fromText("3xa"), - "Option 2: ": me.fromText("4yb"), - "Option 3: ": me.fromText("5zc"), - }; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let q2 = - stateVariables[ - stateVariables["/q2"].replacements[0].componentName - ].activeChildren; - let q2string = q2[0]; - let q2math = me.fromAst( - stateVariables[q2[1].componentName].stateValues.value, - ); - expect(q2math.equals(option[q2string])).eq(true); - - let r2 = - stateVariables[ - stateVariables["/r2"].replacements[0].componentName - ].activeChildren; - let r2string = r2[0]; - let r2math = me.fromAst( - stateVariables[r2[1].componentName].stateValues.value, - ); - expect(r2math.equals(option[r2string])).eq(true); - - let s2 = - stateVariables[ - stateVariables["/s2"].replacements[0].componentName - ].activeChildren; - let s2string = s2[0]; - let s2math = me.fromAst( - stateVariables[s2[1].componentName].stateValues.value, - ); - expect(s2math.equals(option[s2string])).eq(true); - - let t2 = - stateVariables[ - stateVariables["/t2"].replacements[0].componentName - ].activeChildren; - let t2string = t2[0]; - let t2math = me.fromAst( - stateVariables[t2[1].componentName].stateValues.value, - ); - expect(t2math.equals(option[t2string])).eq(true); - - let u2 = - stateVariables[ - stateVariables["/u2"].replacements[0].componentName - ].activeChildren; - let u2string = u2[0]; - let u2math = me.fromAst( - stateVariables[u2[1].componentName].stateValues.value, - ); - expect(u2math.equals(option[u2string])).eq(true); - }); - }); - - it("internal references", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - -

Selected options repeated

- $q{name="q2"} - $r{name="r2"} - $s{name="s2"} - $t{name="t2"} - $u{name="u2"} - -

Copy x from within selection options

-

$(q/x{name="qx"})

-

$(r/x{name="rx"})

-

$(s/x{name="sx"})

-

$(t/x{name="tx"})

-

$(u/x{name="ux"})

- -

Copy select itself

-
$_select1
- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - let option = { - "Option 1: ": me.fromText("3x+a+x^2a^3"), - "Option 2: ": me.fromText("4y+b+y^2b^3"), - "Option 3: ": me.fromText("5z+c+z^2c^3"), - }; - - let xoption = { - "Option 1: ": "x", - "Option 2: ": "y", - "Option 3: ": "z", - }; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let q2 = - stateVariables[ - stateVariables["/q2"].replacements[0].componentName - ].activeChildren; - let q2string = q2[0]; - let q2math = me.fromAst( - stateVariables[q2[1].componentName].stateValues.value, - ); - expect(q2math.equals(option[q2string])).eq(true); - let qx = stateVariables["/qx"].stateValues.value; - expect(qx).eq(xoption[q2string]); - let repeatqmath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[0] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeatqmath.equals(option[q2string])).eq(true); - - let r2 = - stateVariables[ - stateVariables["/r2"].replacements[0].componentName - ].activeChildren; - let r2string = r2[0]; - let r2math = me.fromAst( - stateVariables[r2[1].componentName].stateValues.value, - ); - expect(r2math.equals(option[r2string])).eq(true); - let rx = stateVariables["/rx"].stateValues.value; - expect(rx).eq(xoption[r2string]); - let repeatrmath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[1] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeatrmath.equals(option[r2string])).eq(true); - - let s2 = - stateVariables[ - stateVariables["/s2"].replacements[0].componentName - ].activeChildren; - let s2string = s2[0]; - let s2math = me.fromAst( - stateVariables[s2[1].componentName].stateValues.value, - ); - expect(s2math.equals(option[s2string])).eq(true); - let sx = stateVariables["/sx"].stateValues.value; - expect(sx).eq(xoption[s2string]); - let repeatsmath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[2] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeatsmath.equals(option[s2string])).eq(true); - - let t2 = - stateVariables[ - stateVariables["/t2"].replacements[0].componentName - ].activeChildren; - let t2string = t2[0]; - let t2math = me.fromAst( - stateVariables[t2[1].componentName].stateValues.value, - ); - expect(t2math.equals(option[t2string])).eq(true); - let tx = stateVariables["/tx"].stateValues.value; - expect(tx).eq(xoption[t2string]); - let repeattmath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[3] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeattmath.equals(option[t2string])).eq(true); - - let u2 = - stateVariables[ - stateVariables["/u2"].replacements[0].componentName - ].activeChildren; - let u2string = u2[0]; - let u2math = me.fromAst( - stateVariables[u2[1].componentName].stateValues.value, - ); - expect(u2math.equals(option[u2string])).eq(true); - let ux = stateVariables["/ux"].stateValues.value; - expect(ux).eq(xoption[u2string]); - let repeatumath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[4] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeatumath.equals(option[u2string])).eq(true); - }); - }); - - it("internal references with no new namespace", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - -

Selected options repeated

- $q{name="q2"} - $r{name="r2"} - $s{name="s2"} - $t{name="t2"} - $u{name="u2"} - -

Copy select itself

-
$_select1
- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - let option = { - "Option 1: ": me.fromText("3x+a+x^2a^3"), - "Option 2: ": me.fromText("4y+b+y^2b^3"), - "Option 3: ": me.fromText("5z+c+z^2c^3"), - }; - - let xoption = { - "Option 1: ": "x", - "Option 2: ": "y", - "Option 3: ": "z", - }; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let q2 = - stateVariables[ - stateVariables["/q2"].replacements[0].componentName - ].activeChildren; - let q2string = q2[0]; - let q2math = me.fromAst( - stateVariables[q2[1].componentName].stateValues.value, - ); - expect(q2math.equals(option[q2string])).eq(true); - let repeatqmath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[0] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeatqmath.equals(option[q2string])).eq(true); - - let r2 = - stateVariables[ - stateVariables["/r2"].replacements[0].componentName - ].activeChildren; - let r2string = r2[0]; - let r2math = me.fromAst( - stateVariables[r2[1].componentName].stateValues.value, - ); - expect(r2math.equals(option[r2string])).eq(true); - let repeatrmath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[1] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeatrmath.equals(option[r2string])).eq(true); - - let s2 = - stateVariables[ - stateVariables["/s2"].replacements[0].componentName - ].activeChildren; - let s2string = s2[0]; - let s2math = me.fromAst( - stateVariables[s2[1].componentName].stateValues.value, - ); - expect(s2math.equals(option[s2string])).eq(true); - let repeatsmath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[2] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeatsmath.equals(option[s2string])).eq(true); - - let t2 = - stateVariables[ - stateVariables["/t2"].replacements[0].componentName - ].activeChildren; - let t2string = t2[0]; - let t2math = me.fromAst( - stateVariables[t2[1].componentName].stateValues.value, - ); - expect(t2math.equals(option[t2string])).eq(true); - let repeattmath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[3] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeattmath.equals(option[t2string])).eq(true); - - let u2 = - stateVariables[ - stateVariables["/u2"].replacements[0].componentName - ].activeChildren; - let u2string = u2[0]; - let u2math = me.fromAst( - stateVariables[u2[1].componentName].stateValues.value, - ); - expect(u2math.equals(option[u2string])).eq(true); - let repeatumath = me.fromAst( - stateVariables[ - stateVariables[ - stateVariables["/repeat"].activeChildren[4] - .componentName - ].activeChildren[1].componentName - ].stateValues.value, - ); - expect(repeatumath.equals(option[u2string])).eq(true); - }); - }); - - it("variant names specified, select single", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - -

Selected variable: - -

- -

Selected variable repeated: $x{name="x2"}

-

Selected variable repeated again: $_select1{name="x3"}

- `, - requestedVariantIndex: 2, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - // let variantName = stateVariables['/x'].sharedParameters.variantName; - // let expectedx = variantName.substring(0, 1); - let expectedx = "b"; - - let x = stateVariables["/x"].stateValues.value; - - expect(x).eq(expectedx); - - let xorig = - stateVariables[ - stateVariables[ - stateVariables["/_select1"].replacements[0] - .componentName - ].replacements[0].componentName - ].stateValues.value; - expect(xorig).eq(expectedx); - - let x2 = stateVariables["/x2"].stateValues.value; - expect(x2).eq(expectedx); - - let x3 = - stateVariables[ - stateVariables[ - stateVariables["/x3"].replacements[0].componentName - ].replacements[0].componentName - ].stateValues.value; - expect(x3).eq(expectedx); - }); - }); - - it("variant names specified, select multiple", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - -

Selected variables: - - - -

- -

Selected first variable: $x{name="x2"}

-

Selected second variable: $y{name="y2"}

-

Selected third variable: $z{name="z2"}

-

Selected variables repeated: $_select1{name="s2"}

- - `, - requestedVariantIndex: 3, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let variantMap = { - avocado: ["d", "a", "a"], - broccoli: ["e", "a", "b"], - carrot: ["d", "c", "b"], - dill: ["d", "e", "b"], - eggplant: ["c", "c", "e"], - }; - - // let variantName = stateVariables['/x'].sharedParameters.variantName; - let variantName = "carrot"; - let variantVars = variantMap[variantName]; - - let x = stateVariables["/x"].stateValues.value; - - expect(variantVars.includes(x)).eq(true); - variantVars.splice(variantVars.indexOf(x), 1); - - let y = stateVariables["/y"].stateValues.value; - expect(variantVars.includes(y)).eq(true); - variantVars.splice(variantVars.indexOf(y), 1); - - let z = stateVariables["/z"].stateValues.value; - expect(z).eq(variantVars[0]); - - let xorig = - stateVariables[ - stateVariables[ - stateVariables["/_select1"].replacements[0] - .componentName - ].replacements[0].componentName - ].stateValues.value; - expect(xorig).eq(x); - let yorig = - stateVariables[ - stateVariables[ - stateVariables["/_select1"].replacements[1] - .componentName - ].replacements[0].componentName - ].stateValues.value; - expect(yorig).eq(y); - let zorig = - stateVariables[ - stateVariables[ - stateVariables["/_select1"].replacements[2] - .componentName - ].replacements[0].componentName - ].stateValues.value; - expect(zorig).eq(z); - - let x2 = stateVariables["/x2"].stateValues.value; - expect(x2).eq(x); - let y2 = stateVariables["/y2"].stateValues.value; - expect(y2).eq(y); - let z2 = stateVariables["/z2"].stateValues.value; - expect(z2).eq(z); - - let x3 = - stateVariables[ - stateVariables[ - stateVariables["/s2"].replacements[0].componentName - ].replacements[0].componentName - ].stateValues.value; - expect(x3).eq(x); - let y3 = - stateVariables[ - stateVariables[ - stateVariables["/s2"].replacements[1].componentName - ].replacements[0].componentName - ].stateValues.value; - expect(y3).eq(y); - let z3 = - stateVariables[ - stateVariables[ - stateVariables["/s2"].replacements[2].componentName - ].replacements[0].componentName - ].stateValues.value; - expect(z3).eq(z); - }); - }); - - it("select math as sugared string", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - let options = ["x^2", "x/y", "u", "a", "b-c", "s+t", "mn", "-1"].map( - (x) => me.fromText(x), - ); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let mathsSoFar = []; - for (let ind = 1; ind <= 5; ind++) { - let math = me.fromAst( - stateVariables["/m" + ind].stateValues.value, - ); - expect(options.some((x) => x.equalsViaSyntax(math))).eq(true); - expect(mathsSoFar.some((x) => x.equalsViaSyntax(math))).eq( - false, - ); - mathsSoFar.push(math); - } - }); - }); - - it("select math as sugared string, no type specified", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - let options = ["x^2", "x/y", "u", "a", "b-c", "s+t", "mn", "-1"].map( - (x) => me.fromText(x), - ); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let mathsSoFar = []; - for (let ind = 1; ind <= 5; ind++) { - let math = me.fromAst( - stateVariables["/m" + ind].stateValues.value, - ); - expect(options.some((x) => x.equalsViaSyntax(math))).eq(true); - expect(mathsSoFar.some((x) => x.equalsViaSyntax(math))).eq( - false, - ); - mathsSoFar.push(math); - } - }); - }); - - it("select math as sugared strings and macros", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - x - y - 7 - -3 - - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - let options = ["7x^2", "(-3)x/y", "u-(-3)", "7", "x-c", "y"].map((x) => - me.fromText(x), - ); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let mathsSoFar = []; - for (let ind = 1; ind <= 6; ind++) { - let comp = stateVariables["/m" + ind]; - let math; - if (comp.componentType === "math") { - math = me.fromAst(comp.stateValues.value); - } else { - math = me.fromAst( - stateVariables[comp.replacements[0].componentName] - .stateValues.value, - ); - } - expect(options.some((x) => x.equalsViaSyntax(math))).eq(true); - expect(mathsSoFar.some((x) => x.equalsViaSyntax(math))).eq( - false, - ); - mathsSoFar.push(math); - } - }); - }); - - it("select text as sugared string", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let wordsSoFar = []; - for (let ind = 1; ind <= 5; ind++) { - let word = stateVariables["/w" + ind].stateValues.value; - expect( - [ - "Lorem", - "ipsum", - "dolor", - "sit", - "amet", - "consectetur", - "adipiscing", - "elit", - ].includes(word), - ).eq(true); - expect(wordsSoFar.includes(word)).eq(false); - wordsSoFar.push(word); - } - }); - }); - - it("select text as sugared strings and macros", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - amet - consectetur - dolor - - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let wordsSoFar = []; - for (let ind = 1; ind <= 5; ind++) { - let comp = stateVariables["/w" + ind]; - let word; - if (comp.componentType === "text") { - word = comp.stateValues.value; - } else { - word = - stateVariables[comp.replacements[0].componentName] - .stateValues.value; - } - - expect( - [ - "Lorem", - "ipsum dolor", - "sit", - "amet", - "consectetur adipiscing", - ].includes(word), - ).eq(true); - expect(wordsSoFar.includes(word)).eq(false); - wordsSoFar.push(word); - } - }); - }); - - it("select number as sugared string", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - for (let ind = 1; ind <= 10; ind++) { - let num = stateVariables["/n" + ind].stateValues.value; - expect([2, 3, 5, 7, 11, 13, 17, 19].includes(num)).eq(true); - } - }); - }); - - it("select number as sugared strings and macros", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - 5 - -7 - 6+2 - - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - for (let ind = 1; ind <= 6; ind++) { - let comp = stateVariables["/n" + ind]; - let num; - if (comp.componentType === "number") { - num = comp.stateValues.value; - } else { - num = - stateVariables[comp.replacements[0].componentName] - .stateValues.value; - } - expect([2, -2, -5, 5, -8, 8].includes(num)).eq(true); - } - }); - }); - - it("select boolean as sugared string", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let foundTrue = false, - foundFalse = false; - for (let ind = 1; ind <= 20; ind++) { - let bool = stateVariables["/b" + ind].stateValues.value; - expect([true, false].includes(bool)).eq(true); - if (bool === true) { - foundTrue = true; - } else { - foundFalse = true; - } - } - expect(foundTrue).be.true; - expect(foundFalse).be.true; - }); - }); - - it("select boolean as sugared strings and macros", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - true - false - - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let foundTrue = false, - foundFalse = false; - for (let ind = 1; ind <= 20; ind++) { - let comp = stateVariables["/b" + ind]; - let bool; - if (comp.componentType === "boolean") { - bool = comp.stateValues.value; - } else { - bool = - stateVariables[comp.replacements[0].componentName] - .stateValues.value; - } - expect([true, false].includes(bool)).eq(true); - if (bool === true) { - foundTrue = true; - } else { - foundFalse = true; - } - } - expect(foundTrue).be.true; - expect(foundFalse).be.true; - }); - }); - - it("select invalid type with sugared string, becomes math with warning", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - let options = ["x^2", "x/y", "u", "a", "b-c", "s+t", "mn", "-1"].map( - (x) => me.fromText(x), - ); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let mathsSoFar = []; - for (let ind = 1; ind <= 5; ind++) { - let math = me.fromAst( - stateVariables["/m" + ind].stateValues.value, - ); - expect(options.some((x) => x.equalsViaSyntax(math))).eq(true); - expect(mathsSoFar.some((x) => x.equalsViaSyntax(math))).eq( - false, - ); - mathsSoFar.push(math); - } - }); - - cy.window().then(async (win) => { - let errorWarnings = await win.returnErrorWarnings1(); - - expect(errorWarnings.errors.length).eq(0); - expect(errorWarnings.warnings.length).eq(1); - - expect(errorWarnings.warnings[0].message).contain( - "Invalid type for select: nothing", - ); - expect(errorWarnings.warnings[0].level).eq(1); - expect(errorWarnings.warnings[0].doenetMLrange.lineBegin).eq(4); - expect(errorWarnings.warnings[0].doenetMLrange.charBegin).eq(5); - expect(errorWarnings.warnings[0].doenetMLrange.lineEnd).eq(6); - expect(errorWarnings.warnings[0].doenetMLrange.charEnd).eq(13); - }); - }); - - it("select weighted", () => { - // TODO: this test seems to fail with num Y < 17 once in awhile - // even though it should fail less than 0.1% of the time - // Is there a flaw? - - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", `a`); - - let numX = 0, - numY = 0, - numZ = 0; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - for (let ind = 0; ind < 200; ind++) { - let theText = - stateVariables[ - stateVariables[ - stateVariables[ - stateVariables[ - stateVariables["/_map1"].replacements[ind] - .componentName - ].replacements[1].componentName - ].replacements[0].componentName - ].replacements[0].componentName - ]; - let x = theText.stateValues.value; - if (x === "z") { - numZ++; - } else if (x === "y") { - numY++; - } else { - numX++; - } - } - }); - - cy.window().then(async (win) => { - expect(numX).greaterThan(0); - expect(numX).lessThan(15); - expect(numY).greaterThan(17); - expect(numY).lessThan(50); - expect(numZ).greaterThan(140); - }); - }); - - it("select weighted with replacement", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - `, - requestedVariantIndex: 0, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let numX = 0, - numY = 0, - numZ = 0; - let selectReplacements = stateVariables["/_select1"].replacements; - for (let ind = 0; ind < 200; ind++) { - let x = - stateVariables[ - stateVariables[selectReplacements[ind].componentName] - .replacements[0].componentName - ].stateValues.value; - if (x === "x") { - numX++; - } else if (x === "y") { - numY++; - } else { - numZ++; - } - } - expect(numX).greaterThan(0); - expect(numX).lessThan(15); - expect(numY).greaterThan(20); - expect(numY).lessThan(50); - expect(numZ).greaterThan(150); - }); - }); - - it("select weighted without replacement", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", `a`); - - let numX = 0, - numY = 0, - numZ = 0, - numUVW = 0; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - for (let ind = 0; ind < 200; ind++) { - let theSelect = - stateVariables[ - stateVariables[ - stateVariables["/_map1"].replacements[ind] - .componentName - ].replacements[1].componentName - ]; - let theText1 = - stateVariables[ - stateVariables[theSelect.replacements[0].componentName] - .replacements[0].componentName - ]; - let x = theText1.stateValues.value; - - if (x === "z") { - numZ++; - } else if (x === "y") { - numY++; - } else if (x === "x") { - numX++; - } else { - numUVW++; - } - let theText2 = - stateVariables[ - stateVariables[theSelect.replacements[1].componentName] - .replacements[0].componentName - ]; - let y = theText2.stateValues.value; - if (y === "z") { - numZ++; - } else if (y === "y") { - numY++; - } else if (y === "x") { - numX++; - } else { - numUVW++; - } - } - }); - - cy.window().then(async (win) => { - expect(numUVW).greaterThan(0); - expect(numUVW).lessThan(20); - expect(numX).greaterThan(150); - expect(numY).greaterThan(10); - expect(numY).lessThan(50); - expect(numZ).greaterThan(170); - }); - }); - - it("references to internal assignnames", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - a e i o u$q{name="q2"}$r{name="r2"}

- - - - - -

Selected options repeated

- $q{name="q2"} - $r{name="r2"} - $s{name="s2"} - $t{name="t2"} - $u{name="u2"} - $v{name="v2"} - $w{name="w2"} - -

Copy q and r and their copies from within selected options

-

$(q/q{name="qq"})$(q/r{name="qr"})$(q/q2{name="qq2"})$(q/r2{name="qr2"})

-

$(r/q{name="rq"})$(r/r{name="rr"})$(r/q2{name="rq2"})$(r/r2{name="rr2"})

-

$(s/q{name="sq"})$(s/r{name="sr"})$(s/q2{name="sq2"})$(s/r2{name="sr2"})

-

$(t/q{name="tq"})$(t/r{name="tr"})$(t/q2{name="tq2"})$(t/r2{name="tr2"})

-

$(u/q{name="uq"})$(u/r{name="ur"})$(u/q2{name="uq2"})$(u/r2{name="ur2"})

-

$(v/q{name="vq"})$(v/r{name="vr"})$(v/q2{name="vq2"})$(v/r2{name="vr2"})

-

$(w/q{name="wq"})$(w/r{name="wr"})$(w/q2{name="wq2"})$(w/r2{name="wr2"})

- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let qs = stateVariables["/q"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let rs = stateVariables["/r"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let ss = stateVariables["/s"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let ts = stateVariables["/t"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let us = stateVariables["/u"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let vs = stateVariables["/v"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let ws = stateVariables["/w"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - - let q2s = stateVariables["/q2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let r2s = stateVariables["/r2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let s2s = stateVariables["/s2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let t2s = stateVariables["/t2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let u2s = stateVariables["/u2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let v2s = stateVariables["/v2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let w2s = stateVariables["/w2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - - expect(q2s).eqls(qs); - expect(r2s).eqls(rs); - expect(s2s).eqls(ss); - expect(t2s).eqls(ts); - expect(u2s).eqls(us); - expect(v2s).eqls(vs); - expect(w2s).eqls(ws); - - let q3s = [ - stateVariables["/qq"].stateValues.value, - stateVariables["/qr"].stateValues.value, - stateVariables["/qq2"].stateValues.value, - stateVariables["/qr2"].stateValues.value, - ]; - let r3s = [ - stateVariables["/rq"].stateValues.value, - stateVariables["/rr"].stateValues.value, - stateVariables["/rq2"].stateValues.value, - stateVariables["/rr2"].stateValues.value, - ]; - let s3s = [ - stateVariables["/sq"].stateValues.value, - stateVariables["/sr"].stateValues.value, - stateVariables["/sq2"].stateValues.value, - stateVariables["/sr2"].stateValues.value, - ]; - let t3s = [ - stateVariables["/tq"].stateValues.value, - stateVariables["/tr"].stateValues.value, - stateVariables["/tq2"].stateValues.value, - stateVariables["/tr2"].stateValues.value, - ]; - let u3s = [ - stateVariables["/uq"].stateValues.value, - stateVariables["/ur"].stateValues.value, - stateVariables["/uq2"].stateValues.value, - stateVariables["/ur2"].stateValues.value, - ]; - let v3s = [ - stateVariables["/vq"].stateValues.value, - stateVariables["/vr"].stateValues.value, - stateVariables["/vq2"].stateValues.value, - stateVariables["/vr2"].stateValues.value, - ]; - let w3s = [ - stateVariables["/wq"].stateValues.value, - stateVariables["/wr"].stateValues.value, - stateVariables["/wq2"].stateValues.value, - stateVariables["/wr2"].stateValues.value, - ]; - - expect(q3s).eqls(qs); - expect(r3s).eqls(rs); - expect(s3s).eqls(ss); - expect(t3s).eqls(ts); - expect(u3s).eqls(us); - expect(v3s).eqls(vs); - expect(w3s).eqls(ws); - }); - }); - - it("references to internal assignnames, newnamespaces", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - a e i o u$(s/q{name="q2"})$(s/r{name="r2"})

- - - - -

Selected options repeated

- $q{name="q2"} - $r{name="r2"} - $s{name="s2"} - $t{name="t2"} - $u{name="u2"} - $v{name="v2"} - $w{name="w2"} - -

Selected options repeated, no p

-

$(q/s{name="q3"})

-

$(r/s{name="r3"})

-

$(s/s{name="s3"})

-

$(t/s{name="t3"})

-

$(u/s{name="u3"})

-

$(v/s{name="v3"})

-

$(w/s{name="w3"})

- -

Copy q and r from within selected options

-

$(q/s/q{name="qq"})$(q/s/r{name="qr"})$(q/q2{name="qq2"})$(q/r2{name="qr2"})

-

$(r/s/q{name="rq"})$(r/s/r{name="rr"})$(r/q2{name="rq2"})$(r/r2{name="rr2"})

-

$(s/s/q{name="sq"})$(s/s/r{name="sr"})$(s/q2{name="sq2"})$(s/r2{name="sr2"})

-

$(t/s/q{name="tq"})$(t/s/r{name="tr"})$(t/q2{name="tq2"})$(t/r2{name="tr2"})

-

$(u/s/q{name="uq"})$(u/s/r{name="ur"})$(u/q2{name="uq2"})$(u/r2{name="ur2"})

-

$(v/s/q{name="vq"})$(v/s/r{name="vr"})$(v/q2{name="vq2"})$(v/r2{name="vr2"})

-

$(w/s/q{name="wq"})$(w/s/r{name="wr"})$(w/q2{name="wq2"})$(w/r2{name="wr2"})

- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let qs = stateVariables["/q"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let rs = stateVariables["/r"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let ss = stateVariables["/s"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let ts = stateVariables["/t"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let us = stateVariables["/u"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let vs = stateVariables["/v"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let ws = stateVariables["/w"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - - let q2s = stateVariables["/q2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let r2s = stateVariables["/r2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let s2s = stateVariables["/s2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let t2s = stateVariables["/t2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let u2s = stateVariables["/u2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let v2s = stateVariables["/v2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - let w2s = stateVariables["/w2"].activeChildren.map( - (x) => stateVariables[x.componentName].stateValues.value, - ); - - expect(q2s).eqls(qs); - expect(r2s).eqls(rs); - expect(s2s).eqls(ss); - expect(t2s).eqls(ts); - expect(u2s).eqls(us); - expect(v2s).eqls(vs); - expect(w2s).eqls(ws); - - let q3s = stateVariables["/q3"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let r3s = stateVariables["/r3"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let s3s = stateVariables["/s3"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let t3s = stateVariables["/t3"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let u3s = stateVariables["/u3"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let v3s = stateVariables["/v3"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let w3s = stateVariables["/w3"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - - expect(q3s).eqls(qs.slice(0, 2)); - expect(r3s).eqls(rs.slice(0, 2)); - expect(s3s).eqls(ss.slice(0, 2)); - expect(t3s).eqls(ts.slice(0, 2)); - expect(u3s).eqls(us.slice(0, 2)); - expect(v3s).eqls(vs.slice(0, 2)); - expect(w3s).eqls(ws.slice(0, 2)); - - let q4s = [ - stateVariables["/qq"].stateValues.value, - stateVariables["/qr"].stateValues.value, - stateVariables["/qq2"].stateValues.value, - stateVariables["/qr2"].stateValues.value, - ]; - let r4s = [ - stateVariables["/rq"].stateValues.value, - stateVariables["/rr"].stateValues.value, - stateVariables["/rq2"].stateValues.value, - stateVariables["/rr2"].stateValues.value, - ]; - let s4s = [ - stateVariables["/sq"].stateValues.value, - stateVariables["/sr"].stateValues.value, - stateVariables["/sq2"].stateValues.value, - stateVariables["/sr2"].stateValues.value, - ]; - let t4s = [ - stateVariables["/tq"].stateValues.value, - stateVariables["/tr"].stateValues.value, - stateVariables["/tq2"].stateValues.value, - stateVariables["/tr2"].stateValues.value, - ]; - let u4s = [ - stateVariables["/uq"].stateValues.value, - stateVariables["/ur"].stateValues.value, - stateVariables["/uq2"].stateValues.value, - stateVariables["/ur2"].stateValues.value, - ]; - let v4s = [ - stateVariables["/vq"].stateValues.value, - stateVariables["/vr"].stateValues.value, - stateVariables["/vq2"].stateValues.value, - stateVariables["/vr2"].stateValues.value, - ]; - let w4s = [ - stateVariables["/wq"].stateValues.value, - stateVariables["/wr"].stateValues.value, - stateVariables["/wq2"].stateValues.value, - stateVariables["/wr2"].stateValues.value, - ]; - - expect(q4s).eqls(qs); - expect(r4s).eqls(rs); - expect(s4s).eqls(ss); - expect(t4s).eqls(ts); - expect(u4s).eqls(us); - expect(v4s).eqls(vs); - expect(w4s).eqls(ws); - }); - }); - - // can no longer reference between named grandchildren using their original names - it.skip("references to internal assignnames, named grandchildren", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - 1 - a e i o u$q{name="q2"}$r{name="r2"}

-

a z$q{name="q2"}$r{name="r2"}

- - -

Selected options repeated

-

$q{name="q2"}

-

$r{name="r2"}

-

$s{name="s2"}

-

$t{name="t2"}

-

$u{name="u2"}

- -

Copy x/q and x/r and their copies from within selected options

-

$(q/q{name="qq2"})$(q/r{name="qr2"})$qq{name="qq3"}$qr{name="qr3"}

-

$(r/q{name="rq2"})$(r/r{name="rr2"})$rq{name="rq3"}$rr{name="rr3"}

-

$(s/q{name="sq2"})$(s/r{name="sr2"})$sq{name="sq3"}$sr{name="sr3"}

-

$(t/q{name="tq2"})$(t/r{name="tr2"})$tq{name="tq3"}$tr{name="tr3"}

-

$(u/q{name="uq2"})$(u/r{name="ur2"})$uq{name="uq3"}$ur{name="ur3"}

- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/u\\/r")) - .invoke("text") - .then((text) => { - expect(text.length).equal(1); - }); - cy.get(cesc("#\\/_math1") + " .mjx-mrow") - .eq(0) - .invoke("text") - .then((text) => { - expect(text.trim()).equal("1"); - }); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let qs = stateVariables["/q"].replacements.map( - (x) => x.stateValues.value, - ); - let rs = stateVariables["/r"].replacements.map( - (x) => x.stateValues.value, - ); - let ss = stateVariables["/s"].replacements.map( - (x) => x.stateValues.value, - ); - let ts = stateVariables["/t"].replacements.map( - (x) => x.stateValues.value, - ); - let us = stateVariables["/u"].replacements.map( - (x) => x.stateValues.value, - ); - - let q2s = stateVariables["/q2"].replacements.map( - (x) => x.stateValues.value, - ); - let r2s = stateVariables["/r2"].replacements.map( - (x) => x.stateValues.value, - ); - let s2s = stateVariables["/s2"].replacements.map( - (x) => x.stateValues.value, - ); - let t2s = stateVariables["/t2"].replacements.map( - (x) => x.stateValues.value, - ); - let u2s = stateVariables["/u2"].replacements.map( - (x) => x.stateValues.value, - ); - - expect(q2s).eqls(qs); - expect(r2s).eqls(rs); - expect(s2s).eqls(ss); - expect(t2s).eqls(ts); - expect(u2s).eqls(us); - - let q3s = [ - stateVariables[ - stateVariables["/qq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/qr2"].replacements[0].componentName - ].stateValues.value, - ]; - let q4s = [ - stateVariables[ - stateVariables["/qq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/qr3"].replacements[0].componentName - ].stateValues.value, - ]; - let r3s = [ - stateVariables[ - stateVariables["/rq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/rr2"].replacements[0].componentName - ].stateValues.value, - ]; - let r4s = [ - stateVariables[ - stateVariables["/rq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/rr3"].replacements[0].componentName - ].stateValues.value, - ]; - let s3s = [ - stateVariables[ - stateVariables["/sq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/sr2"].replacements[0].componentName - ].stateValues.value, - ]; - let s4s = [ - stateVariables[ - stateVariables["/sq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/sr3"].replacements[0].componentName - ].stateValues.value, - ]; - let t3s = [ - stateVariables[ - stateVariables["/tq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/tr2"].replacements[0].componentName - ].stateValues.value, - ]; - let t4s = [ - stateVariables[ - stateVariables["/tq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/tr3"].replacements[0].componentName - ].stateValues.value, - ]; - let u3s = [ - stateVariables[ - stateVariables["/uq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/ur2"].replacements[0].componentName - ].stateValues.value, - ]; - let u4s = [ - stateVariables[ - stateVariables["/uq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/ur3"].replacements[0].componentName - ].stateValues.value, - ]; - - expect(q3s).eqls(qs); - expect(r3s).eqls(rs); - expect(s3s).eqls(ss); - expect(t3s).eqls(ts); - expect(u3s).eqls(us); - - expect(q4s).eqls(qs); - expect(r4s).eqls(rs); - expect(s4s).eqls(ss); - expect(t4s).eqls(ts); - expect(u4s).eqls(us); - }); - }); - - // can no longer reference between named grandchildren using their original names - it.skip("references to internal assignnames, newnamespaces, named grandchildren", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - 1 - a e i o u$(a/q{name="q2"})$(a/r{name="r2"})

-

a z$(b/q{name="q2"})$(b/r{name="r2"})

- - -

Selected options repeated

-

$q{name="q2"}

-

$r{name="r2"}

-

$s{name="s2"}

-

$t{name="t2"}

-

$u{name="u2"}

- -

Copy x/q and x/r and their copies from within selected options

-

$(q/q{name="qq2"})$(q/r{name="qr2"})$qq{name="qq3"}$qr{name="qr3"}

-

$(r/q{name="rq2"})$(r/r{name="rr2"})$rq{name="rq3"}$rr{name="rr3"}

-

$(s/q{name="sq2"})$(s/r{name="sr2"})$sq{name="sq3"}$sr{name="sr3"}

-

$(t/q{name="tq2"})$(t/r{name="tr2"})$tq{name="tq3"}$tr{name="tr3"}

-

$(u/q{name="uq2"})$(u/r{name="ur2"})$uq{name="uq3"}$ur{name="ur3"}

- - - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/u\\/r")) - .invoke("text") - .then((text) => { - expect(text.length).equal(1); - }); - cy.get(cesc("#\\/_math1") + " .mjx-mrow") - .eq(0) - .invoke("text") - .then((text) => { - expect(text.trim()).equal("1"); - }); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let qs = stateVariables["/q"].replacements.map( - (x) => x.stateValues.value, - ); - let rs = stateVariables["/r"].replacements.map( - (x) => x.stateValues.value, - ); - let ss = stateVariables["/s"].replacements.map( - (x) => x.stateValues.value, - ); - let ts = stateVariables["/t"].replacements.map( - (x) => x.stateValues.value, - ); - let us = stateVariables["/u"].replacements.map( - (x) => x.stateValues.value, - ); - - let q2s = stateVariables["/q2"].replacements.map( - (x) => x.stateValues.value, - ); - let r2s = stateVariables["/r2"].replacements.map( - (x) => x.stateValues.value, - ); - let s2s = stateVariables["/s2"].replacements.map( - (x) => x.stateValues.value, - ); - let t2s = stateVariables["/t2"].replacements.map( - (x) => x.stateValues.value, - ); - let u2s = stateVariables["/u2"].replacements.map( - (x) => x.stateValues.value, - ); - - expect(q2s).eqls(qs); - expect(r2s).eqls(rs); - expect(s2s).eqls(ss); - expect(t2s).eqls(ts); - expect(u2s).eqls(us); - - let q3s = [ - stateVariables[ - stateVariables["/qq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/qr2"].replacements[0].componentName - ].stateValues.value, - ]; - let q4s = [ - stateVariables[ - stateVariables["/qq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/qr3"].replacements[0].componentName - ].stateValues.value, - ]; - let r3s = [ - stateVariables[ - stateVariables["/rq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/rr2"].replacements[0].componentName - ].stateValues.value, - ]; - let r4s = [ - stateVariables[ - stateVariables["/rq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/rr3"].replacements[0].componentName - ].stateValues.value, - ]; - let s3s = [ - stateVariables[ - stateVariables["/sq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/sr2"].replacements[0].componentName - ].stateValues.value, - ]; - let s4s = [ - stateVariables[ - stateVariables["/sq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/sr3"].replacements[0].componentName - ].stateValues.value, - ]; - let t3s = [ - stateVariables[ - stateVariables["/tq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/tr2"].replacements[0].componentName - ].stateValues.value, - ]; - let t4s = [ - stateVariables[ - stateVariables["/tq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/tr3"].replacements[0].componentName - ].stateValues.value, - ]; - let u3s = [ - stateVariables[ - stateVariables["/uq2"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/ur2"].replacements[0].componentName - ].stateValues.value, - ]; - let u4s = [ - stateVariables[ - stateVariables["/uq3"].replacements[0].componentName - ].stateValues.value, - stateVariables[ - stateVariables["/ur3"].replacements[0].componentName - ].stateValues.value, - ]; - - expect(q3s).eqls(qs); - expect(r3s).eqls(rs); - expect(s3s).eqls(ss); - expect(t3s).eqls(ts); - expect(u3s).eqls(us); - - expect(q4s).eqls(qs); - expect(r4s).eqls(rs); - expect(s4s).eqls(ss); - expect(t4s).eqls(ts); - expect(u4s).eqls(us); - }); - }); - - it("references to select of selects", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - a e i o u - - - -

Selected options repeated

-

$q{name="q2"}

-

$r{name="r2"}

-

$s{name="s2"}

-

$t{name="t2"}

-

$u{name="u2"}

- -

Copy x/q and x/r

-

$(q/q{name="qq"})$(q/r{name="qr"})

-

$(r/q{name="rq"})$(r/r{name="rr"})

-

$(s/q{name="sq"})$(s/r{name="sr"})

-

$(t/q{name="tq"})$(t/r{name="tr"})

-

$(u/q{name="uq"})$(u/r{name="ur"})

- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let qs = stateVariables["/q"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let rs = stateVariables["/r"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let ss = stateVariables["/s"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let ts = stateVariables["/t"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let us = stateVariables["/u"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - - let q2s = stateVariables["/q2"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let r2s = stateVariables["/r2"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let s2s = stateVariables["/s2"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let t2s = stateVariables["/t2"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - let u2s = stateVariables["/u2"].replacements - .map((x) => stateVariables[x.componentName]) - .map((x) => - x.replacements - ? stateVariables[x.replacements[0].componentName] - .stateValues.value - : x.stateValues.value, - ); - - expect(q2s).eqls(qs); - expect(r2s).eqls(rs); - expect(s2s).eqls(ss); - expect(t2s).eqls(ts); - expect(u2s).eqls(us); - - let q3s = [ - stateVariables["/qq"].stateValues.value, - stateVariables["/qr"].stateValues.value, - ]; - let r3s = [ - stateVariables["/rq"].stateValues.value, - stateVariables["/rr"].stateValues.value, - ]; - let s3s = [ - stateVariables["/sq"].stateValues.value, - stateVariables["/sr"].stateValues.value, - ]; - let t3s = [ - stateVariables["/tq"].stateValues.value, - stateVariables["/tr"].stateValues.value, - ]; - let u3s = [ - stateVariables["/uq"].stateValues.value, - stateVariables["/ur"].stateValues.value, - ]; - - expect(q3s).eqls(qs); - expect(r3s).eqls(rs); - expect(s3s).eqls(ss); - expect(t3s).eqls(ts); - expect(u3s).eqls(us); - }); - }); - - it("references to select of selects of selects", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - - - - - - -

Selected options repeated

-

$q{name="q2"}

-

$r{name="r2"}

-

$s{name="s2"}

- -

Copy x/q, x/r, x/s

-

$(q/q{name="qq"})$(q/r{name="qr"})$(q/s{name="qs"})

-

$(r/q{name="rq"})$(r/r{name="rr"})$(r/s{name="rs"})

-

$(s/q{name="sq"})$(s/r{name="sr"})$(s/s{name="ss"})

- -

Copy x/x/q, x/x/r

-

$(q/q/q{name="qqq"})$(q/q/r{name="qqr"})$(q/r/q{name="qrq"})$(q/r/r{name="qrr"})$(q/s/q{name="qsq"})$(q/s/r{name="qsr"})

-

$(r/q/q{name="rqq"})$(r/q/r{name="rqr"})$(r/r/q{name="rrq"})$(r/r/r{name="rrr"})$(r/s/q{name="rsq"})$(r/s/r{name="rsr"})

-

$(s/q/q{name="sqq"})$(s/q/r{name="sqr"})$(s/r/q{name="srq"})$(s/r/r{name="srr"})$(s/s/q{name="ssq"})$(s/s/r{name="ssr"})

- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let qs = [ - "/q/q/q", - "/q/q/r", - "/q/r/q", - "/q/r/r", - "/q/s/q", - "/q/s/r", - ].map((x) => - stateVariables[x].replacements - ? stateVariables[ - stateVariables[x].replacements[0].componentName - ].stateValues.value - : stateVariables[x].stateValues.value, - ); - let rs = [ - "/r/q/q", - "/r/q/r", - "/r/r/q", - "/r/r/r", - "/r/s/q", - "/r/s/r", - ].map((x) => - stateVariables[x].replacements - ? stateVariables[ - stateVariables[x].replacements[0].componentName - ].stateValues.value - : stateVariables[x].stateValues.value, - ); - let ss = [ - "/s/q/q", - "/s/q/r", - "/s/r/q", - "/s/r/r", - "/s/s/q", - "/s/s/r", - ].map((x) => - stateVariables[x].replacements - ? stateVariables[ - stateVariables[x].replacements[0].componentName - ].stateValues.value - : stateVariables[x].stateValues.value, - ); - - cy.get(cesc("#\\/pq2")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(qs.join("")); - }); - cy.get(cesc("#\\/pr2")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(rs.join("")); - }); - cy.get(cesc("#\\/ps2")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(ss.join("")); - }); - - cy.get(cesc("#\\/pq3")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(qs.join("")); - }); - cy.get(cesc("#\\/pr3")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(rs.join("")); - }); - cy.get(cesc("#\\/ps3")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(ss.join("")); - }); - - cy.get(cesc("#\\/pq4")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(qs.join("")); - }); - cy.get(cesc("#\\/pr4")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(rs.join("")); - }); - cy.get(cesc("#\\/ps4")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(ss.join("")); - }); - }); - }); - - it("references to select of selects of selects, newnamespaces", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - - - - - - -

Selected options repeated

-

$(a/q{name="q2"})

-

$(a/r{name="r2"})

-

$(a/s{name="s2"})

- -

Copy x/q, x/r, x/s

-

$(a/q/q{name="qq"})$(a/q/r{name="qr"})$(a/q/s{name="qs"})

-

$(a/r/q{name="rq"})$(a/r/r{name="rr"})$(a/r/s{name="rs"})

-

$(a/s/q{name="sq"})$(a/s/r{name="sr"})$(a/s/s{name="ss"})

- -

Copy x/x/q, x/x/r

-

$(a/q/q/q{name="qqq"})$(a/q/q/r{name="qqr"})$(a/q/r/q{name="qrq"})$(a/q/r/r{name="qrr"})$(a/q/s/q{name="qsq"})$(a/q/s/r{name="qsr"})

-

$(a/r/q/q{name="rqq"})$(a/r/q/r{name="rqr"})$(a/r/r/q{name="rrq"})$(a/r/r/r{name="rrr"})$(a/r/s/q{name="rsq"})$(a/r/s/r{name="rsr"})

-

$(a/s/q/q{name="sqq"})$(a/s/q/r{name="sqr"})$(a/s/r/q{name="srq"})$(a/s/r/r{name="srr"})$(a/s/s/q{name="ssq"})$(a/s/s/r{name="ssr"})

- - `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_text1")).should("have.text", "a"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let qs = [ - "/a/q/q/q", - "/a/q/q/r", - "/a/q/r/q", - "/a/q/r/r", - "/a/q/s/q", - "/a/q/s/r", - ].map((x) => - stateVariables[x].replacements - ? stateVariables[ - stateVariables[x].replacements[0].componentName - ].stateValues.value - : stateVariables[x].stateValues.value, - ); - let rs = [ - "/a/r/q/q", - "/a/r/q/r", - "/a/r/r/q", - "/a/r/r/r", - "/a/r/s/q", - "/a/r/s/r", - ].map((x) => - stateVariables[x].replacements - ? stateVariables[ - stateVariables[x].replacements[0].componentName - ].stateValues.value - : stateVariables[x].stateValues.value, - ); - let ss = [ - "/a/s/q/q", - "/a/s/q/r", - "/a/s/r/q", - "/a/s/r/r", - "/a/s/s/q", - "/a/s/s/r", - ].map((x) => - stateVariables[x].replacements - ? stateVariables[ - stateVariables[x].replacements[0].componentName - ].stateValues.value - : stateVariables[x].stateValues.value, - ); - - cy.get(cesc("#\\/pq2")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(qs.join("")); - }); - cy.get(cesc("#\\/pr2")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(rs.join("")); - }); - cy.get(cesc("#\\/ps2")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(ss.join("")); - }); - - cy.get(cesc("#\\/pq3")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(qs.join("")); - }); - cy.get(cesc("#\\/pr3")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(rs.join("")); - }); - cy.get(cesc("#\\/ps3")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(ss.join("")); - }); - - cy.get(cesc("#\\/pq4")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(qs.join("")); - }); - cy.get(cesc("#\\/pr4")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(rs.join("")); - }); - cy.get(cesc("#\\/ps4")) - .invoke("text") - .then((text) => { - expect(text.replace(/, /g, "")).eq(ss.join("")); - }); - }); - }); - - it("references to named grandchildren's children", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - -

Copy grandchidren

-

$a{name="a2"}

-

$b{name="b2"}

-

$c{name="c2"}

-

$d{name="d2"}

- -

Copy named children of grandchild

-

$(a/w{name="w2"})

-

$(b/v{name="v2"})

- - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - let options = [ - { - a: "x y", - b: "3 z", - c: "x", - d: "z", - v: "z", - w: "x", - }, - { - a: "u v", - b: "3 t", - c: "u", - d: "t", - v: "t", - w: "u", - }, - ]; - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let chosenChildren = stateVariables[ - stateVariables["/_select1"].replacements[0].componentName - ].replacements - .filter((x) => typeof x !== "string") - .map((x) => stateVariables[x.componentName]) - .map((v, i) => - i < 2 ? v : stateVariables[v.replacements[0].componentName], - ); - let option = - options[ - stateVariables["/_select1"].stateValues.selectedIndices[0] - - 1 - ]; - - expect( - me.fromAst(chosenChildren[0].stateValues.value).toString(), - ).eq(option.a); - expect( - me.fromAst(chosenChildren[1].stateValues.value).toString(), - ).eq(option.b); - expect( - me.fromAst(chosenChildren[2].stateValues.value).toString(), - ).eq(option.c); - expect( - me.fromAst(chosenChildren[3].stateValues.value).toString(), - ).eq(option.d); - - let a2 = me - .fromAst(stateVariables["/a2"].stateValues.value) - .toString(); - let b2 = me - .fromAst(stateVariables["/b2"].stateValues.value) - .toString(); - let c2 = me - .fromAst(stateVariables["/c2"].stateValues.value) - .toString(); - let d2 = me - .fromAst(stateVariables["/d2"].stateValues.value) - .toString(); - let v2 = me - .fromAst(stateVariables["/v2"].stateValues.value) - .toString(); - let w2 = me - .fromAst(stateVariables["/w2"].stateValues.value) - .toString(); - - expect(a2).eq(option.a); - expect(b2).eq(option.b); - expect(c2).eq(option.c); - expect(d2).eq(option.d); - expect(v2).eq(option.v); - expect(w2).eq(option.w); - }); - }); - - it("select of a map of a select, with references", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a -

- -

- -

Copy whole select again

-

$_select1{name="s2"}

- -

Copy individual selections

-

- $j{name="j2"} - $k{name="k2"} - $l{name="l2"} -

- -

Copy individual pieces

-

- $(j/a/p{name="p1"})$(j/a/q{name="p2"})$(j/a/r{name="p3"})$(j/a/s{name="p4"})$(j/b/p{name="p5"})$(j/b/q{name="p6"})$(j/b/r{name="p7"})$(j/b/s{name="p8"}) - $(k/a/p{name="p9"})$(k/a/q{name="p10"})$(k/a/r{name="p11"})$(k/a/s{name="p12"})$(k/b/p{name="p13"})$(k/b/q{name="p14"})$(k/b/r{name="p15"})$(k/b/s{name="p16"}) - $(l/a/p{name="p17"})$(l/a/q{name="p18"})$(l/a/r{name="p19"})$(l/a/s{name="p20"})$(l/b/p{name="p21"})$(l/b/q{name="p22"})$(l/b/r{name="p23"})$(l/b/s{name="p24"}) -

- `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let theList1 = stateVariables["/list1"].activeChildren.map((x) => - me - .fromAst(stateVariables[x.componentName].stateValues.value) - .toString(), - ); - let theList2 = stateVariables["/list2"].activeChildren.map((x) => - me - .fromAst(stateVariables[x.componentName].stateValues.value) - .toString(), - ); - let theList3 = stateVariables["/list3"].activeChildren.map((x) => - me - .fromAst(stateVariables[x.componentName].stateValues.value) - .toString(), - ); - - expect(theList2).eqls(theList1); - expect(theList3).eqls(theList1); - - let theList4 = [...Array(24).keys()].map((i) => - me - .fromAst(stateVariables["/p" + (i + 1)].stateValues.value) - .toString(), - ); - - expect(theList4).eqls(theList1); - }); - }); - - it("select of a map of a select, new namespaces", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a -

- -

- -

Copy whole select again

-

$s{name="s2"}

- -

Copy individual selections

-

- $(s/j{name="j2"}) - $(s/k{name="k2"}) - $(s/l{name="l2"}) -

- -

Copy individual pieces

-

- $(s/j/a/v/p{name="p1"})$(s/j/a/v/q{name="p2"})$(s/j/a/v/r{name="p3"})$(s/j/a/v/s{name="p4"})$(s/j/b/v/p{name="p5"})$(s/j/b/v/q{name="p6"})$(s/j/b/v/r{name="p7"})$(s/j/b/v/s{name="p8"}) - $(s/k/a/v/p{name="p9"})$(s/k/a/v/q{name="p10"})$(s/k/a/v/r{name="p11"})$(s/k/a/v/s{name="p12"})$(s/k/b/v/p{name="p13"})$(s/k/b/v/q{name="p14"})$(s/k/b/v/r{name="p15"})$(s/k/b/v/s{name="p16"}) - $(s/l/a/v/p{name="p17"})$(s/l/a/v/q{name="p18"})$(s/l/a/v/r{name="p19"})$(s/l/a/v/s{name="p20"})$(s/l/b/v/p{name="p21"})$(s/l/b/v/q{name="p22"})$(s/l/b/v/r{name="p23"})$(s/l/b/v/s{name="p24"}) -

- `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let theList1 = stateVariables["/list1"].activeChildren.map((x) => - me - .fromAst(stateVariables[x.componentName].stateValues.value) - .toString(), - ); - let theList2 = stateVariables["/list2"].activeChildren.map((x) => - me - .fromAst(stateVariables[x.componentName].stateValues.value) - .toString(), - ); - let theList3 = stateVariables["/list3"].activeChildren.map((x) => - me - .fromAst(stateVariables[x.componentName].stateValues.value) - .toString(), - ); - - expect(theList2).eqls(theList1); - expect(theList3).eqls(theList1); - - let theList4 = [...Array(24).keys()].map((i) => - me - .fromAst(stateVariables["/p" + (i + 1)].stateValues.value) - .toString(), - ); - - expect(theList4).eqls(theList1); - }); - }); - - it("select with hide will hide replacements but not copies", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` -

Selects and hide

-

,

-

$c, $d

- `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_p1")).should("have.text", "Selects and hide"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let c = await stateVariables["/c"].stateValues.value; - let d = await stateVariables["/d"].stateValues.value; - expect(["a", "b", "c", "d", "e"].includes(c)).eq(true); - expect(["a", "b", "c", "d", "e"].includes(d)).eq(true); - - cy.get(cesc(`#\\/_p2`)).should("have.text", `${c}, `); - cy.get(cesc(`#\\/_p3`)).should("have.text", `${c}, ${d}`); - }); - }); - - it("select with hide will hide named grandchildren replacements but not copies", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` -

Selects and hide

-

-

$a, , $c, , $e

- `, - }, - "*", - ); - }); - - // to wait for page to load - cy.get(cesc("#\\/_p1")).should("have.text", "Selects and hide"); - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let a = stateVariables["/a"].stateValues.value; - let b = stateVariables["/b"].stateValues.value; - let c = stateVariables["/c"].stateValues.value; - let d = stateVariables["/d"].stateValues.value; - let e = stateVariables["/e"].stateValues.value; - expect(["a", "d"].includes(a)).eq(true); - expect(["b", "e"].includes(b)).eq(true); - expect(["c", "f"].includes(c)).eq(true); - expect(["a", "c", "e"].includes(d)).eq(true); - expect(["b", "d", "f"].includes(e)).eq(true); - - cy.get(cesc(`#\\/_p2`)).should("have.text", `${a}, ${b}, ${c}`); - cy.get(cesc(`#\\/_p3`)).should( - "have.text", - `${a}, , ${c}, ${d}, ${e}`, - ); - }); - }); - - it("selects hide dynamically", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - - -

,

-

$c, $d

- `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let c = await stateVariables["/c"].stateValues.value; - let d = await stateVariables["/d"].stateValues.value; - expect(["a", "b", "c", "d", "e"].includes(c)).eq(true); - expect(["a", "b", "c", "d", "e"].includes(d)).eq(true); - - cy.get(cesc(`#\\/_p1`)).should("have.text", `${c}, `); - cy.get(cesc(`#\\/_p2`)).should("have.text", `${c}, ${d}`); - - cy.get(cesc("#\\/h1")).click(); - cy.get(cesc("#\\/h2")).click(); - - cy.get(cesc(`#\\/_p1`)).should("have.text", `, ${d}`); - cy.get(cesc(`#\\/_p2`)).should("have.text", `${c}, ${d}`); - - cy.get(cesc("#\\/h1")).click(); - cy.get(cesc("#\\/h2")).click(); - - cy.get(cesc(`#\\/_p1`)).should("have.text", `${c}, `); - cy.get(cesc(`#\\/_p2`)).should("have.text", `${c}, ${d}`); - }); - }); - - it("string and blank strings in options", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - foxjumps - elephanttrumpets - - -

a:

- -

a1: $a{assignNames="a11 a12 a13 a14"}

- -

pieces: -

q,r =

- - -

q2 = $q

-

r2 = $r

- - - - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let replacements = - stateVariables[ - stateVariables["/_select1"].replacements[0].componentName - ].replacements; - - let p1 = replacements[1].componentName; - let p2 = replacements[3].componentName; - let p3 = replacements[5].componentName; - - cy.get(cesc2("#" + p1)).should("have.text", `q,r = ab`); - cy.get(cesc2("#" + p2)).should("have.text", `q2 = a`); - cy.get(cesc2("#" + p3)).should("have.text", `r2 = b`); - }); - }); - - it("display error when miss a name in selectForVariants, inside text", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - - -

We have a !

- `, - }, - "*", - ); - }); - - cy.get(cesc2("#/_p1")).should("contain.text", "We have a "); - cy.get(cesc2("#/_p1")).should("contain.text", "!"); - cy.get(cesc2("#/_p1")).should( - "contain.text", - "Some variants are specified for select but no options are specified for possible variant name: banana", - ); - cy.get(cesc2("#/_p1")).should("contain.text", "lines 4–7"); - - cy.window().then(async (win) => { - let errorWarnings = await win.returnErrorWarnings1(); - - expect(errorWarnings.errors.length).eq(1); - expect(errorWarnings.warnings.length).eq(0); - - expect(errorWarnings.errors[0].message).contain( - "Some variants are specified for select but no options are specified for possible variant name: banana", - ); - expect(errorWarnings.errors[0].doenetMLrange.lineBegin).eq(4); - expect(errorWarnings.errors[0].doenetMLrange.charBegin).eq(24); - expect(errorWarnings.errors[0].doenetMLrange.lineEnd).eq(7); - expect(errorWarnings.errors[0].doenetMLrange.charEnd).eq(13); - }); - }); - - it("display error when repeat name in selectForVariants more times than numToSelect, inside p", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - - -

We have a !

- `, - }, - "*", - ); - }); - - cy.get(cesc2("#/_p1")).should("contain.text", "We have a "); - cy.get(cesc2("#/_p1")).should("contain.text", "!"); - cy.get(cesc2("#/_p1")).should( - "contain.text", - "Invalid variant name for select. Variant name apple appears in 2 options but number to select is 1", - ); - cy.get(cesc2("#/_p1")).should("contain.text", "lines 4–7"); - - cy.window().then(async (win) => { - let errorWarnings = await win.returnErrorWarnings1(); - - expect(errorWarnings.errors.length).eq(1); - expect(errorWarnings.warnings.length).eq(0); - - expect(errorWarnings.errors[0].message).contain( - "Invalid variant name for select. Variant name apple appears in 2 options but number to select is 1", - ); - expect(errorWarnings.errors[0].doenetMLrange.lineBegin).eq(4); - expect(errorWarnings.errors[0].doenetMLrange.charBegin).eq(18); - expect(errorWarnings.errors[0].doenetMLrange.lineEnd).eq(7); - expect(errorWarnings.errors[0].doenetMLrange.charEnd).eq(13); - }); - }); - - it("display error when repeat name in selectForVariants more times than numToSelect, inside document", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - - - We have a ! - `, - }, - "*", - ); - }); - - cy.get(cesc2("#/_document1")).should("contain.text", "We have a "); - cy.get(cesc2("#/_document1")).should("contain.text", "!"); - cy.get(cesc2("#/_document1")).should( - "contain.text", - "Variant name donut that is specified for select is not a possible variant name", - ); - cy.get(cesc2("#/_document1")).should("contain.text", "lines 4–8"); - - cy.window().then(async (win) => { - let errorWarnings = await win.returnErrorWarnings1(); - - expect(errorWarnings.errors.length).eq(1); - expect(errorWarnings.warnings.length).eq(0); - - expect(errorWarnings.errors[0].message).contain( - "Variant name donut that is specified for select is not a possible variant name", - ); - expect(errorWarnings.errors[0].doenetMLrange.lineBegin).eq(4); - expect(errorWarnings.errors[0].doenetMLrange.charBegin).eq(15); - expect(errorWarnings.errors[0].doenetMLrange.lineEnd).eq(8); - expect(errorWarnings.errors[0].doenetMLrange.charEnd).eq(13); - }); - }); - - it("display error when numToSelect is larger than number of options, inside graph", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` -

No points for graph!

- - - `, - }, - "*", - ); - }); - - cy.get(cesc2("#/_p1")).should("contain.text", "No points for graph!"); - cy.get(cesc2("#/_document1")).should( - "contain.text", - "Cannot select 3 components from only 2", - ); - cy.get(cesc2("#/_document1")).should("contain.text", "lines 4–7"); - - cy.window().then(async (win) => { - let errorWarnings = await win.returnErrorWarnings1(); - - expect(errorWarnings.errors.length).eq(1); - expect(errorWarnings.warnings.length).eq(0); - - expect(errorWarnings.errors[0].message).contain( - "Cannot select 3 components from only 2", - ); - expect(errorWarnings.errors[0].doenetMLrange.lineBegin).eq(4); - expect(errorWarnings.errors[0].doenetMLrange.charBegin).eq(12); - expect(errorWarnings.errors[0].doenetMLrange.lineEnd).eq(7); - expect(errorWarnings.errors[0].doenetMLrange.charEnd).eq(13); - }); - }); - - it("numToSelect from selectfromsequence", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - -

n1 =

-

vars =

-

a1=$a1, b1=$b1, c1=$c1, d1=$d1, e1=$e1

- -

n2 =

-

vars =

-

a2=$a2, b2=$b2, c2=$c2, d2=$d2, e2=$e2

- -

n3 =

-

vars =

-

a3=$a3, b3=$b3, c3=$c3, d3=$d3, e3=$e3

- -

n4 =

-

vars =

-

a4=$a4, b4=$b4, c4=$c4, d4=$d4, e4=$e4

- -

n5 =

-

vars =

-

a5=$a5, b5=$b5, c5=$c5, d5=$d5, e5=$e5

- `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - let n1 = stateVariables["/n1"].stateValues.value; - let n2 = stateVariables["/n2"].stateValues.value; - let n3 = stateVariables["/n3"].stateValues.value; - let n4 = stateVariables["/n4"].stateValues.value; - let n5 = stateVariables["/n5"].stateValues.value; - - let vars1 = stateVariables["/vars1"].replacements.map( - (x) => - stateVariables[ - stateVariables[x.componentName].replacements[0] - .componentName - ].stateValues.value, - ); - let vars2 = stateVariables["/vars2"].replacements.map( - (x) => - stateVariables[ - stateVariables[x.componentName].replacements[0] - .componentName - ].stateValues.value, - ); - let vars3 = stateVariables["/vars3"].replacements.map( - (x) => - stateVariables[ - stateVariables[x.componentName].replacements[0] - .componentName - ].stateValues.value, - ); - let vars4 = stateVariables["/vars4"].replacements.map( - (x) => - stateVariables[ - stateVariables[x.componentName].replacements[0] - .componentName - ].stateValues.value, - ); - let vars5 = stateVariables["/vars5"].replacements.map( - (x) => - stateVariables[ - stateVariables[x.componentName].replacements[0] - .componentName - ].stateValues.value, - ); - - expect(vars1.length).eq(n1); - expect(vars2.length).eq(n2); - expect(vars3.length).eq(n3); - expect(vars4.length).eq(n4); - expect(vars5.length).eq(n5); - - vars1.length = 5; - vars2.length = 5; - vars3.length = 5; - vars4.length = 5; - vars5.length = 5; - - vars1.fill("", n1); - vars2.fill("", n2); - vars3.fill("", n3); - vars4.fill("", n4); - vars5.fill("", n5); - - let l = ["a", "b", "c", "d", "e"]; - - cy.get(cesc("#\\/p1")).should( - "have.text", - vars1.map((v, i) => `${l[i]}1=${v}`).join(", "), - ); - cy.get(cesc("#\\/p2")).should( - "have.text", - vars2.map((v, i) => `${l[i]}2=${v}`).join(", "), - ); - cy.get(cesc("#\\/p3")).should( - "have.text", - vars3.map((v, i) => `${l[i]}3=${v}`).join(", "), - ); - cy.get(cesc("#\\/p4")).should( - "have.text", - vars4.map((v, i) => `${l[i]}4=${v}`).join(", "), - ); - cy.get(cesc("#\\/p5")).should( - "have.text", - vars5.map((v, i) => `${l[i]}5=${v}`).join(", "), - ); - }); - }); - - it("add level to assign names even in shadow", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a -

- - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let q = stateVariables["/q"].stateValues.value; - - expect(stateVariables["/c/q"].stateValues.value).eq(q); - }); - }); - - it("ensure unique names", () => { - cy.window().then(async (win) => { - win.postMessage( - { - doenetML: ` - a - - - - - - `, - }, - "*", - ); - }); - - cy.get(cesc("#\\/_text1")).should("have.text", "a"); // to wait for page to load - - cy.window().then(async (win) => { - let stateVariables = await win.returnAllStateVariables1(); - - let pNames1 = stateVariables["/_select1"].replacements.map( - (x) => - stateVariables[x.componentName].replacements[0] - .componentName, - ); - for (let pn of pNames1) { - cy.get(cesc2("#" + pn)).should("have.text", "What is this?"); - } - - let pNames2 = ["/A", "/B", "/C"].map( - (x) => stateVariables[x].replacements[0].componentName, - ); - for (let pn of pNames2) { - cy.get(cesc2("#" + pn)).should("have.text", "What is this?"); - } - - for (let pn of ["/D", "/E", "/F"]) { - cy.get(cesc2("#" + pn)).should("have.text", "What is this?"); - } - }); - }); });