diff --git a/curriculum/package-lock.json b/curriculum/package-lock.json index e682f3fe60..cf48196651 100644 --- a/curriculum/package-lock.json +++ b/curriculum/package-lock.json @@ -38,10 +38,12 @@ "puppeteer": "^8.0.0", "readdirp": "^3.5.0", "rehype": "^11.0.0", - "rework-visit": "^1.0.0", "string-similarity": "^4.0.2", "unist-util-visit": "^2.0.3", "vfile": "^4.2.0" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@babel/code-frame": { @@ -8090,12 +8092,6 @@ "node": ">=0.12" } }, - "node_modules/rework-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", - "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=", - "dev": true - }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -16669,12 +16665,6 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, - "rework-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", - "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=", - "dev": true - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", diff --git a/curriculum/package.json b/curriculum/package.json index f3c4b2e5e1..6c6f81a12e 100644 --- a/curriculum/package.json +++ b/curriculum/package.json @@ -55,7 +55,6 @@ "puppeteer": "^8.0.0", "readdirp": "^3.5.0", "rehype": "^11.0.0", - "rework-visit": "^1.0.0", "string-similarity": "^4.0.2", "unist-util-visit": "^2.0.3", "vfile": "^4.2.0" diff --git a/curriculum/schema/challengeSchema.js b/curriculum/schema/challengeSchema.js index e46c87ae2f..72e1ff8799 100644 --- a/curriculum/schema/challengeSchema.js +++ b/curriculum/schema/challengeSchema.js @@ -27,6 +27,8 @@ const schema = Joi.object() challengeOrder: Joi.number(), challengeType: Joi.number().min(0).max(11).required(), checksum: Joi.number(), + // __commentCounts is only used to test the comment replacement + __commentCounts: Joi.object(), // TODO: require this only for normal challenges, not certs dashedName: Joi.string().regex(slugRE), description: Joi.when('challengeType', { diff --git a/curriculum/test/test-challenges.js b/curriculum/test/test-challenges.js index c1762e1c17..c022066f35 100644 --- a/curriculum/test/test-challenges.js +++ b/curriculum/test/test-challenges.js @@ -24,7 +24,7 @@ const { const { assert, AssertionError } = require('chai'); const Mocha = require('mocha'); -const { flatten, isEmpty, cloneDeep } = require('lodash'); +const { flatten, isEmpty, cloneDeep, isEqual } = require('lodash'); const { getLines } = require('../../utils/get-lines'); const jsdom = require('jsdom'); @@ -62,12 +62,14 @@ const TRANSLATABLE_COMMENTS = getTranslatableComments( // the config files are created during the build, but not before linting // eslint-disable-next-line import/no-unresolved const testEvaluator = require('../../config/client/test-evaluator').filename; +const { inspect } = require('util'); const commentExtractors = { html: require('./utils/extract-html-comments'), js: require('./utils/extract-js-comments'), jsx: require('./utils/extract-jsx-comments'), - css: require('./utils/extract-css-comments') + css: require('./utils/extract-css-comments'), + scriptJs: require('./utils/extract-script-js-comments') }; // rethrow unhandled rejections to make sure the tests exit with -1 @@ -329,7 +331,7 @@ function populateTestsForLang({ lang, challenges, meta }) { // We get all the actual comments using the appropriate parsers if (file.ext === 'html') { - const commentTypes = ['css', 'html']; + const commentTypes = ['css', 'html', 'scriptJs']; for (let type of commentTypes) { const newComments = commentExtractors[type](file.contents); for (const [key, value] of Object.entries(newComments)) { @@ -342,17 +344,22 @@ function populateTestsForLang({ lang, challenges, meta }) { comments = commentExtractors[file.ext](file.contents); } - // Then we compare the number of times a given comment appears - // (count) with the number of times the text within it appears - // (commentTextCount) - for (const [comment, count] of Object.entries(comments)) { - const commentTextCount = - file.contents.split(comment).length - 1; - if (commentTextCount !== count) - throw Error( - `Translated comment text, ${comment}, should only appear inside comments` - ); - } + // Then we compare the number of times each comment appears in the + // translated text (commentMap) with the number of replacements + // made during translation (challenge.__commentCounts). If they + // differ, the translation must have gone wrong + + const commentMap = new Map(Object.entries(comments)); + + if (isEmpty(challenge.__commentCounts) && isEmpty(commentMap)) + return; + + if (!isEqual(commentMap, challenge.__commentCounts)) + throw Error(`Mismatch in ${challenge.title}. Replaced comments: +${inspect(challenge.__commentCounts)} +Comments in translated text: +${inspect(commentMap)} +`); }); }); diff --git a/curriculum/test/utils/extract-css-comments.test.js b/curriculum/test/utils/extract-css-comments.test.js index 70d71e8081..52088f2137 100644 --- a/curriculum/test/utils/extract-css-comments.test.js +++ b/curriculum/test/utils/extract-css-comments.test.js @@ -19,6 +19,39 @@ Some text
+Some text + + +Some text + + +Some text + + +// comment 2 +