diff --git a/client/src/client/frame-runner.js b/client/src/client/frame-runner.ts similarity index 65% rename from client/src/client/frame-runner.js rename to client/src/client/frame-runner.ts index 7b0f074c7e..228ec37c3c 100644 --- a/client/src/client/frame-runner.js +++ b/client/src/client/frame-runner.ts @@ -2,17 +2,42 @@ import '@babel/polyfill'; import jQuery from 'jquery'; import curriculumHelpers from '../utils/curriculum-helpers'; +declare global { + interface Window { + $: JQueryStatic; + } + interface Document { + // eslint-disable-next-line @typescript-eslint/naming-convention + __initTestFrame: (e: InitTestFrameArg) => Promise; + // eslint-disable-next-line @typescript-eslint/naming-convention + __runTest: ( + testString: string + ) => Promise< + { pass: boolean } | { err: { message: string; stack?: string } } + >; + } +} + window.$ = jQuery; document.__initTestFrame = initTestFrame; -async function initTestFrame(e = { code: {} }) { +export interface InitTestFrameArg { + code: { + contents?: string; + editableContents?: string; + }; + getUserInput?: (fileName: string) => string; + loadEnzyme?: () => void; +} + +async function initTestFrame(e: InitTestFrameArg = { code: {} }) { const code = (e.code.contents || '').slice(); const editableContents = (e.code.editableContents || '').slice(); // __testEditable allows test authors to run tests against a transitory dom // element built using only the code in the editable region. - // eslint-disable-next-line no-unused-vars - const __testEditable = cb => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const __testEditable = (cb: () => () => unknown) => { const div = document.createElement('div'); div.id = 'editable-only'; div.innerHTML = editableContents; @@ -26,12 +51,14 @@ async function initTestFrame(e = { code: {} }) { e.getUserInput = () => code; } - /* eslint-disable no-unused-vars */ + /* eslint-disable @typescript-eslint/no-unused-vars */ // Fake Deep Equal dependency - const DeepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b); + const DeepEqual = (a: Record, b: Record) => + JSON.stringify(a) === JSON.stringify(b); // Hardcode Deep Freeze dependency - const DeepFreeze = o => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const DeepFreeze = (o: Record) => { Object.freeze(o); Object.getOwnPropertyNames(o).forEach(function (prop) { if ( @@ -50,10 +77,11 @@ async function initTestFrame(e = { code: {} }) { const { default: chai } = await import(/* webpackChunkName: "chai" */ 'chai'); const assert = chai.assert; const __helpers = curriculumHelpers; - /* eslint-enable no-unused-vars */ + /* eslint-enable @typescript-eslint/no-unused-vars */ let Enzyme; if (e.loadEnzyme) { + /* eslint-disable prefer-const */ let Adapter16; /* eslint-disable no-inline-comments */ @@ -64,9 +92,10 @@ async function initTestFrame(e = { code: {} }) { /* eslint-enable no-inline-comments */ Enzyme.configure({ adapter: new Adapter16() }); + /* eslint-enable prefer-const */ } - document.__runTest = async function runTests(testString) { + document.__runTest = async function runTests(testString: string) { // uncomment the following line to inspect // the frame-runner as it runs tests // make sure the dev tools console is open @@ -81,7 +110,7 @@ async function initTestFrame(e = { code: {} }) { $(() => { try { // eslint-disable-next-line no-eval - const test = eval(testString); + const test: unknown = eval(testString); resolve(test); } catch (err) { reject(err); @@ -102,10 +131,10 @@ async function initTestFrame(e = { code: {} }) { // actual before returning return { err: { - message: err.message, - stack: err.stack, - expected: err.expected, - actual: err.actual + message: (err as Error).message, + stack: (err as Error).stack, + expected: (err as { expected?: string }).expected, + actual: (err as { actual?: string }).actual } }; } diff --git a/client/webpack-workers.js b/client/webpack-workers.js index 4e7cc53375..e810ac0e8d 100644 --- a/client/webpack-workers.js +++ b/client/webpack-workers.js @@ -11,7 +11,7 @@ module.exports = (env = {}) => { cache: __DEV__ ? { type: 'filesystem' } : false, mode: __DEV__ ? 'development' : 'production', entry: { - 'frame-runner': './src/client/frame-runner.js', + 'frame-runner': './src/client/frame-runner.ts', 'sass-compile': './src/client/workers/sass-compile.ts', 'test-evaluator': './src/client/workers/test-evaluator.ts' }, diff --git a/package-lock.json b/package-lock.json index ff8aeed769..af72788a48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,9 +24,12 @@ "@testing-library/jest-dom": "5.15.1", "@testing-library/user-event": "13.5.0", "@types/chai": "4.2.22", + "@types/enzyme": "^3.10.10", + "@types/enzyme-adapter-react-16": "^1.0.6", "@types/faker": "5.5.9", "@types/inquirer": "8.1.3", "@types/jest": "27.0.3", + "@types/jquery": "^3.5.9", "@types/loadable__component": "5.13.4", "@types/lodash-es": "4.17.5", "@types/node": "16.11.11", @@ -7200,6 +7203,34 @@ "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", "dev": true }, + "node_modules/@types/cheerio": { + "version": "0.22.30", + "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.30.tgz", + "integrity": "sha512-t7ZVArWZlq3dFa9Yt33qFBQIK4CQd1Q3UJp0V+UhP6vgLWLM6Qug7vZuRSGXg45zXeB1Fm5X2vmBkEX58LV2Tw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/enzyme": { + "version": "3.10.10", + "resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.10.tgz", + "integrity": "sha512-/D4wFhiEjUDfPu+j5FVK0g/jf7rqeEIpNfAI+kyxzLpw5CKO0drnW3W5NC38alIjsWgnyQ8pbuPF5+UD+vhVyg==", + "dev": true, + "dependencies": { + "@types/cheerio": "*", + "@types/react": "*" + } + }, + "node_modules/@types/enzyme-adapter-react-16": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.6.tgz", + "integrity": "sha512-VonDkZ15jzqDWL8mPFIQnnLtjwebuL9YnDkqeCDYnB4IVgwUm0mwKkqhrxLL6mb05xm7qqa3IE95m8CZE9imCg==", + "dev": true, + "dependencies": { + "@types/enzyme": "*" + } + }, "node_modules/@types/faker": { "version": "5.5.9", "resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.9.tgz", @@ -7406,6 +7437,15 @@ "node": ">=8" } }, + "node_modules/@types/jquery": { + "version": "3.5.9", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.9.tgz", + "integrity": "sha512-B8pDk+sH/tSv/HKdx6EQER6BfUOb2GtKs0LOmozziS4h7cbe8u/eYySfUAeTwD+J09SqV3man7AMWIA5mgzCBA==", + "dev": true, + "dependencies": { + "@types/sizzle": "*" + } + }, "node_modules/@types/jsdom": { "version": "16.2.13", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.13.tgz", @@ -29251,6 +29291,34 @@ "integrity": "sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==", "dev": true }, + "@types/cheerio": { + "version": "0.22.30", + "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.30.tgz", + "integrity": "sha512-t7ZVArWZlq3dFa9Yt33qFBQIK4CQd1Q3UJp0V+UhP6vgLWLM6Qug7vZuRSGXg45zXeB1Fm5X2vmBkEX58LV2Tw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/enzyme": { + "version": "3.10.10", + "resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.10.tgz", + "integrity": "sha512-/D4wFhiEjUDfPu+j5FVK0g/jf7rqeEIpNfAI+kyxzLpw5CKO0drnW3W5NC38alIjsWgnyQ8pbuPF5+UD+vhVyg==", + "dev": true, + "requires": { + "@types/cheerio": "*", + "@types/react": "*" + } + }, + "@types/enzyme-adapter-react-16": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.6.tgz", + "integrity": "sha512-VonDkZ15jzqDWL8mPFIQnnLtjwebuL9YnDkqeCDYnB4IVgwUm0mwKkqhrxLL6mb05xm7qqa3IE95m8CZE9imCg==", + "dev": true, + "requires": { + "@types/enzyme": "*" + } + }, "@types/faker": { "version": "5.5.9", "resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.9.tgz", @@ -29412,6 +29480,15 @@ } } }, + "@types/jquery": { + "version": "3.5.9", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.9.tgz", + "integrity": "sha512-B8pDk+sH/tSv/HKdx6EQER6BfUOb2GtKs0LOmozziS4h7cbe8u/eYySfUAeTwD+J09SqV3man7AMWIA5mgzCBA==", + "dev": true, + "requires": { + "@types/sizzle": "*" + } + }, "@types/jsdom": { "version": "16.2.13", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.13.tgz", diff --git a/package.json b/package.json index 5a0dd368e0..cefd5ca49a 100644 --- a/package.json +++ b/package.json @@ -103,9 +103,12 @@ "@testing-library/jest-dom": "5.15.1", "@testing-library/user-event": "13.5.0", "@types/chai": "4.2.22", + "@types/enzyme": "^3.10.10", + "@types/enzyme-adapter-react-16": "^1.0.6", "@types/faker": "5.5.9", "@types/inquirer": "8.1.3", "@types/jest": "27.0.3", + "@types/jquery": "^3.5.9", "@types/loadable__component": "5.13.4", "@types/lodash-es": "4.17.5", "@types/node": "16.11.11",