@khanacademy/perseus 17.6.1 → 17.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Core Perseus API (includes renderers and widgets)",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "17.6.1",
6
+ "version": "17.7.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -24,7 +24,7 @@
24
24
  "dependencies": {
25
25
  "@khanacademy/kas": "^0.3.7",
26
26
  "@khanacademy/kmath": "^0.1.8",
27
- "@khanacademy/math-input": "^16.4.1",
27
+ "@khanacademy/math-input": "^16.5.0",
28
28
  "@khanacademy/perseus-core": "1.4.1",
29
29
  "@khanacademy/perseus-linter": "^0.3.10",
30
30
  "@khanacademy/pure-markdown": "^0.2.13",
@@ -48,6 +48,26 @@ const createItemJson = (
48
48
  };
49
49
  };
50
50
 
51
+ export const expressionItemWithAnswer = (answer: string): PerseusItem => {
52
+ return createItemJson(
53
+ {
54
+ answerForms: [
55
+ {
56
+ considered: "correct",
57
+ form: false,
58
+ simplify: false,
59
+ value: answer,
60
+ },
61
+ ],
62
+ times: false,
63
+ buttonSets: ["basic"],
64
+ functions: [],
65
+ buttonsVisible: "always",
66
+ },
67
+ {major: 1, minor: 0},
68
+ );
69
+ };
70
+
51
71
  export const expressionItem2: PerseusItem = createItemJson(
52
72
  {
53
73
  answerForms: [
@@ -12,6 +12,7 @@ import {
12
12
  expressionItem2,
13
13
  expressionItem3,
14
14
  expressionItem3Options,
15
+ expressionItemWithAnswer,
15
16
  } from "../__testdata__/expression.testdata";
16
17
  import {Expression} from "../expression";
17
18
 
@@ -182,6 +183,33 @@ describe("Expression Widget", function () {
182
183
  });
183
184
  });
184
185
 
186
+ describe("when the question uses the sin function", () => {
187
+ it("allows parens", () => {
188
+ const item = expressionItemWithAnswer("sin(x)");
189
+ assertCorrect(item, "sin(x)");
190
+ });
191
+
192
+ it("allows no parens", () => {
193
+ const item = expressionItemWithAnswer("sin(x)");
194
+ assertCorrect(item, "sin x");
195
+ });
196
+
197
+ it("grades a wrong answer as incorrect", () => {
198
+ const item = expressionItemWithAnswer("sin(x)");
199
+ assertIncorrect(item, "2");
200
+ });
201
+
202
+ it("treats sen as equivalent to sin", () => {
203
+ const item = expressionItemWithAnswer("sin(x)");
204
+ assertCorrect(item, "sen x");
205
+ });
206
+
207
+ it("treats multiple usages of sen as equivalent to sin", () => {
208
+ const item = expressionItemWithAnswer("sin(sin(x))");
209
+ assertCorrect(item, "sen(sen(x))");
210
+ });
211
+ });
212
+
185
213
  describe("analytics", () => {
186
214
  const assertKeypadVersion = (
187
215
  apiOptions: APIOptions,
@@ -436,4 +464,21 @@ describe("error tooltip", () => {
436
464
  screen.getByText("Sorry, I don't understand that!"),
437
465
  ).toBeVisible();
438
466
  });
467
+
468
+ it("does not show error text when the sen() function is used (Portuguese for sin())", async () => {
469
+ // Arrange
470
+ const {renderer} = renderQuestion(expressionItem2.question);
471
+ const expression = renderer.findWidgets("expression 1")[0];
472
+
473
+ // Act
474
+ expression.insert("sen(x)");
475
+ screen.getByRole("textbox").blur();
476
+ renderer.guessAndScore();
477
+
478
+ // Assert
479
+ expect(screen.queryByText("Oops!")).toBeNull();
480
+ expect(
481
+ screen.queryByText("Sorry, I don't understand that!"),
482
+ ).toBeNull();
483
+ });
439
484
  });
@@ -57,6 +57,17 @@ const insertBraces = (value) => {
57
57
  return value.replace(/([_^])([^{])/g, "$1{$2}");
58
58
  };
59
59
 
60
+ const anglicizeOperators = (tex: string): string => {
61
+ // sen is used instead of sin in some languages, e.g. Portuguese.
62
+ // To ensure that answers in various languages are graded correctly, we
63
+ // convert operators to their Englishy forms.
64
+ return tex.replace(/\\operatorname{sen}/g, "\\sin ");
65
+ };
66
+
67
+ const normalizeTex = (tex: string): string => {
68
+ return anglicizeOperators(insertBraces(tex));
69
+ };
70
+
60
71
  const deriveKeypadVersion = (apiOptions: APIOptions) => {
61
72
  // We can derive which version of the keypad is in use. This is
62
73
  // a bit tricky, but this code will be relatively short-lived
@@ -280,7 +291,7 @@ export class Expression extends React.Component<Props, ExpressionState> {
280
291
  }
281
292
 
282
293
  static getUserInputFromProps(props: Props): string {
283
- return insertBraces(props.value);
294
+ return normalizeTex(props.value);
284
295
  }
285
296
 
286
297
  static getOneCorrectAnswerFromRubric(
@@ -410,7 +421,7 @@ export class Expression extends React.Component<Props, ExpressionState> {
410
421
  _.extend(options, {
411
422
  decimal_separator: i18n.getDecimalSeparator(),
412
423
  });
413
- return KAS.parse(insertBraces(value), options);
424
+ return KAS.parse(normalizeTex(value), options);
414
425
  };
415
426
 
416
427
  changeAndTrack: (e: any, cb: () => void) => void = (
@@ -67,8 +67,8 @@ export default class Marker extends React.Component<Props> {
67
67
 
68
68
  const iconNull: IconType = {
69
69
  path: "",
70
- height: 0,
71
- width: 0,
70
+ height: 1,
71
+ width: 1,
72
72
  };
73
73
 
74
74
  // default dot